Giai đoạn một cuộc đảo chính để trở thành vua của ngọn đồi!


14

Bảng xếp hạng

  154 Calculator
  144 Taxman
  138 Statistician
  137 Solver
  137 RandoAggroLawyer
  136 Gambler
  134 Turncoat
  119 Lawyer
  119 BloodyMurder
  113 Bandit
   79 Challenger
   74 Mask
   64 Random

Một kho lưu trữ của trận đấu mới nhất, bao gồm nhật ký và tất cả các tệp đầu ra, có sẵn.

Máy tính, bởi Brilliand, là người chiến thắng! Câu trả lời của anh ấy được chấp nhận, nhưng điều đó không có nghĩa là thử thách đã kết thúc. Vui lòng gửi các mục mới hoặc chỉnh sửa các mục hiện tại của bạn và cố gắng đánh bật ngai vàng của anh ấy. Tôi sẽ trao một khoản tiền thưởng cho nhà lãnh đạo vào cuối tháng.

Luật chơi

Coup là một trò chơi bài được thiết kế cho 2-6 người chơi, chúng ta sẽ chơi với hai người. Nó bao gồm một kho tiền xu (vô hạn cho mục đích của chúng tôi) và một bộ gồm 15 thẻ, chứa 3 loại sau: Đại sứ, Sát thủ, Thuyền trưởng, Contessa, Duke. Khi bắt đầu trò chơi, mỗi người chơi được phát một đồng xu và chia hai lá bài ngẫu nhiên, họ giữ bí mật cho đến khi cần thiết. Đối tượng là người chơi cuối cùng có thẻ trong tay bạn.

Đến lượt mình, người chơi có thể thực hiện một trong các hành động sau bất kể thẻ của họ là gì:

  • Thu nhập: lấy 1 xu từ kho bạc. Không thể chặn và không thể vượt qua.
  • Viện trợ nước ngoài: lấy 2 xu từ kho bạc. Có thể bị chặn bởi một người chơi với Công tước. Không thể vượt qua.
  • Cuộc đảo chính: Loại bỏ một thẻ của một đối thủ bạn chọn khỏi chơi. Chi phí 7 xu. Nạn nhân có thể chọn loại thẻ nào để loại bỏ. Nếu người chơi có từ 10 đồng xu trở lên khi bắt đầu lượt chơi, họ phải đảo chính. Không thể chặn và không thể vượt qua.

Tùy thuộc vào thẻ của họ, người chơi cũng có thể thực hiện một trong các hành động sau đây lần lượt:

  • Trao đổi: một người chơi có Đại sứ có thể lấy hai thẻ từ bộ bài. Sau đó, họ có thể chọn từ tay của mình và các thẻ được rút ra nhiều thẻ như ban đầu. (Nghĩa là, nếu họ chỉ có một thẻ, họ có thể đổi nó lấy một trong những thẻ đã rút hoặc giữ nó, và nếu họ có hai thẻ, họ có thể chọn bất kỳ hai trong bốn thẻ.) Hai thẻ không mong muốn được trả lại cho bộ bài . Không thể chặn, nhưng thách thức.
  • Sát thủ: một người chơi có Sát thủ có thể chi 3 xu để xóa thẻ của đối thủ khỏi trò chơi. Nạn nhân có thể chọn loại thẻ nào để loại bỏ. Có thể bị chặn bởi người chơi có Contessa, trong trường hợp đó, tiền không được trả lại. Thách thức, trong trường hợp tiền được trả lại.
  • Ăn cắp: Một người chơi có Thuyền trưởng có thể lấy hai đồng xu từ đối thủ của họ. Nếu đối thủ có một đồng, họ sẽ lấy một đồng đó. Nếu đối thủ không có xu, họ có thể không Ăn cắp. Có thể bị chặn bởi người chơi có Đại sứ hoặc Thuyền trưởng. Thử thách.
  • Thuế: Một người chơi có Công tước có thể lấy 3 đồng xu từ kho bạc. Không thể chặn, nhưng thách thức.

Phần khó khăn của Coup là người chơi được phép nói dối về những thẻ bài họ có! Bạn không cần phải có thẻ để cố gắng thực hiện hành động hoặc chặn liên quan đến nó.

Khi người chơi thực hiện hành động của thẻ, bất kỳ đối thủ nào (ngay cả một người không bị tổn hại bởi hành động đó) có thể thách thức diễn viên và nói rằng họ không tin rằng họ có thẻ cho hành động đó. Nếu người thách đấu là chính xác, hành động sẽ bị hủy và diễn viên phải loại bỏ một thẻ theo lựa chọn của họ (lấy lại bất kỳ đồng tiền nào họ đã chi nếu có). Nếu không, hành động được thực hiện, diễn viên trả lại thẻ mà họ bị thách thức lên boong và rút một cái mới, và người thách đấu phải loại bỏ một trong những thẻ của họ. Người chơi phải trung thực về những thẻ bài họ giữ khi bị thách đấu.

Các lá bài bị loại khỏi cuộc chơi với Assassination, Coup và các thử thách bị mất không được trả lại cho bộ bài, nhưng các lá bài được tiết lộ là một phần của một thử thách giành chiến thắng được đưa trở lại bộ bài.

Các khối có thể được thử thách giống như hành động. Ví dụ: nếu người chơi A yêu cầu Viện trợ nước ngoài và người chơi B nói "Tôi có Công tước và tôi chặn Viện trợ nước ngoài của bạn", A có thể nói "Tôi không tin rằng bạn có Công tước". Nếu khẳng định đó là đúng, B sẽ mất một thẻ vì bị nói dối và A mất 2 xu; nếu không, A mất một thẻ và không nhận được tiền, và B phải trả lại Công tước của họ cho bộ bài và rút một thẻ mới.

Cách thức các khối và thử thách hoạt động với Assassination phải được bổ sung. Giả sử Người chơi A nói "Tôi có Sát thủ và Tôi ám sát Người chơi B". Nếu B không cố gắng thách thức hoặc chặn A, thì vụ ám sát sẽ diễn ra: B mất thẻ và A trả 3 xu.

Ngoài ra, B có thể thách thức bằng cách nói "Tôi không tin rằng bạn có Sát thủ". Nếu đó là sự thật, thì A sẽ loại bỏ một thẻ và tiền của họ được trả lại, trong khi B không bị ảnh hưởng và lượt của A kết thúc. Nếu niềm tin của B là không chính xác và A giữ một Assassin, thì B sẽ mất cả hai thẻ của họ và thất bại, một cho thử thách không chính xác và một cho ám sát.

Thay vì thử thách, B có thể nói "Tôi có một Contessa và tôi chặn Kẻ ám sát". Nếu A tin B, thì lượt của A kết thúc và tiền của họ không được trả lại. Nhưng A có thể thách thức khối và nói "Tôi không tin rằng bạn có Contessa." Nếu B thực tế giữ một Contessa, thì A sẽ mất một thẻ cho thử thách không chính xác. Nhưng nếu B không, thì B sẽ mất một thẻ vì bị nói dối và một thẻ khác từ Vụ ám sát.

Logic tương tự như lời giải thích ở trên áp dụng cho khả năng Steal của Captain, trong đó hành động hoặc khối có thể bị thách thức.

Có thể mất cả hai thẻ của bạn và bị loại trong một lượt, nếu bạn không thành công thách thức một Kẻ ám sát hoặc bạn bị bắt khi tuyên bố rằng bạn có một Contessa để chặn một vụ ám sát. Bạn mất một thẻ từ thử thách và một thẻ từ Vụ ám sát.

Thử thách

Nhiệm vụ của bạn là viết một chương trình sẽ chơi Coup. Nó sẽ được đưa ra như là đối số dòng lệnh của nó:

  • Tên của một tệp chứa danh sách các hành động của nó và đối thủ của nó cho đến nay.
  • Một số nguyên từ 0 đến 12 cho biết số xu của đối thủ.
  • Một số nguyên từ 0 đến 12 chỉ số đếm xu của nó.
  • Một chuỗi dài từ một đến bốn ký tự chỉ ra các thẻ của nó. Thông thường, đây chỉ đơn giản là một hoặc hai thẻ mà chương trình của bạn có, nhưng nếu chương trình của bạn vừa thành công tại Sàn giao dịch, nó sẽ dài n + 2 ký tự, trong đó n là số thẻ còn lại của bạn. Chương trình của bạn sau đó phải xuất ra n thẻ mà nó muốn giữ thành STDOUT. (Các chương trình không được đọc hoặc truy cập STDOUT ngoài mục đích này - nếu bạn muốn tạo đầu ra gỡ lỗi, vui lòng ghi vào STDERR.)
  • Một hoặc nhiều đối số chỉ ra các động thái pháp lý mà nó có thể thực hiện.

(Ví dụ gọi : yourprogram file.txt 1 7 '~!' a c p q, có nghĩa là "Đối thủ của bạn có 1 xu. Bạn có 7 xu, Đại sứ và Contessa. Viết vào file.txt bạn chọn a, c, p hoặc q với lịch sử trò chơi và trạng thái trò chơi hiện tại. ")

Chương trình của bạn phải nối thêm một hoặc (trong hai tình huống cụ thể) hai ký tự vào tệp được cung cấp cho biết hành động của nó. Nó không được thay đổi nội dung hiện có của tập tin. Nó có thể tạo bất kỳ tập tin mới nào nó muốn, nhưng chỉ trong thư mục mà nó được chạy. Vui lòng cung cấp tất cả các lệnh cần thiết để biên dịch và chạy chương trình của bạn.

Tôi đã cung cấp hai ví dụ đối thủ cạnh tranh dưới đây, được viết bằng Go.

Định dạng đầu ra là:

  • I\n: Thu nhập = earnings. Phản ứng pháp lý: bất kỳ hành động lần lượt nào (giả sử người ta có tiền cho Assassination / Coup).
  • F: Viện trợ nước ngoài. Phản ứng pháp lý: d(chặn như một Công tước), p(để nó qua).
  • C: Cuộc đảo chính. Phản ứng theo pháp luật: bất cứ của _, ', <, =, 0là trong tay của bạn.
  • E: Đổi. Phản hồi pháp lý: q(thách thức, không tin người chơi có Đại sứ) p,.
  • T: Thuế. Phản ứng pháp lý: q(thách thức, không tin người chơi có Công tước) p,.
  • A: Ám sát. Phản ứng theo pháp luật: s(khối như một Contessa), q(thách thức), và bất cứ của _, ', <, =, 0là trong tay của bạn.
  • S: Lấy trộm. Phản hồi về mặt pháp lý: a(chặn làm Đại sứ), c(chặn làm Thuyền trưởng), q(thách thức, không tin người chơi có Thuyền trưởng) , p.
  • d: chặn Viện trợ nước ngoài như một Công tước. Phản ứng pháp lý: \n(chấp nhận khối), q(thách thức, không tin người chơi có Công tước).
  • a: chặn Steal làm Đại sứ. Phản ứng pháp lý: \n(chấp nhận khối), q(thách thức, không tin người chơi có Đại sứ).
  • c: chặn Steal làm Thuyền trưởng. \n(chấp nhận chặn), q(thách thức, không tin người chơi có Thuyền trưởng).
  • s: chặn một Kẻ ám sát như một Contessa. Phản hồi pháp lý: \n(chấp nhận chặn), q(thách thức, không tin người chơi có Contessa).
  • p: vượt qua thử thách Trao đổi / Thuế / Ăn cắp khi không đến lượt bạn. Không được sử dụng với A; từ chối thách thức một Assassination viết một trong số đó _'<=0. Phản hồi pháp lý: \n(kết thúc lượt của bạn) và nếu bạn vừa thành công tại Sàn giao dịch, hãy viết các thẻ bạn muốn giữ từ đối số dòng lệnh thứ tư sang STDOUT.
  • q: thách thức hành động hoặc khối gần đây nhất. Phản ứng pháp lý: nếu bạn có thẻ cho hành động bị thách thức, bất kể ~^*!$đó là hành động nào . Nếu bạn không, thì bất cứ điều gì _'<=0từ tay bạn muốn từ bỏ, tiếp theo là một dòng mới nếu và chỉ khi đến lượt bạn.
  • ~, ^, *, !, $: Tiết lộ rằng bạn đang nói sự thật về tổ chức, tương ứng, một đại sứ, một Assassin, một thuyền trưởng, một Contessa và Duke (còn sử dụng để đại diện cho các thẻ này trong đối số dòng lệnh, và STDOUT đầu ra trong Exchange ). Phản ứng theo pháp luật: bất cứ của _, ', <, =, 0bạn có trong tay của bạn.
  • _, ', <, =, 0: Từ bỏ như sự trừng phạt, tương ứng, một Đại sứ, và Assassin, một thuyền trưởng, một Contessa và Duke vì bạn mất một thách thức hoặc bị ám sát / Couped. Phản ứng pháp lý : \n.
  • \n: kết thúc lượt của bạn, làm như vậy từ chối để thách thức một khối nếu có. Phản hồi về mặt pháp lý: mọi hành động viết hoa (giả sử người ta có tiền cho Assassination / Coup và đối thủ có tiền cho Steal).

Định dạng có các thuộc tính hữu ích sau:

  • Lần lượt bắt đầu với một chữ in hoa.
  • Các dòng theo mẫu: chữ in hoa, chữ thường, dấu chấm câu tùy chọn hoặc 0 cho các thẻ được tiết lộ, dòng mới.
  • Một tệp kết thúc bằng một dòng mới hoặc một tệp trống, cho biết rằng đó là bắt đầu lượt của chương trình của bạn và nó phải chọn một hành động viết hoa.
  • Các hành động pháp lý mà bạn được phép thực hiện một yêu cầu thường được xác định duy nhất bởi ký tự cuối cùng trong tệp. Ngoại lệ là q, sẽ có một số logic liên quan đến nó. Xem chức năng get_legal_actionstrong trọng tài để giúp hiểu điều này. Hoặc bạn chỉ có thể sử dụng các hành động pháp lý bạn đưa ra trên dòng lệnh.
  • Số lượng ký tự chẵn trên một dòng cho biết lượt chơi là của bạn và chương trình của bạn được yêu cầu chọn một hành động, thách thức một khối hoặc kết thúc lượt của nó.
  • Số lượng ký tự lẻ trên một dòng cho biết rằng lượt chơi không phải của bạn và chương trình của bạn được yêu cầu chặn, thách thức hoặc tiết lộ / đầu hàng thẻ.

Tôi sẽ đưa ra một ví dụ cho mọi hành động.

I\nlà dễ hiểu nhất. Một chương trình lấy một xu Thu nhập, sau đó kết thúc lượt của nó. Đây là một trong hai trường hợp các chương trình phải in hai ký tự, vì Thu nhập là hành động duy nhất mà đối thủ không bị ảnh hưởng và không thể chặn hoặc thách thức.

Fp\ncó nghĩa là một chương trình đã lấy Viện trợ nước ngoài, sau đó đối thủ của nó đã từ chối chặn ( p). Trong lần gọi tiếp theo, chương trình đầu tiên lưu ý rằng bằng chữ thường cuối cùng pvà / hoặc số ký tự chẵn trên dòng này, đến lượt nó, nó vẫn chưa kết thúc, vì vậy nó biết kết thúc lượt hiện tại của mình bằng cách in một dòng mới.

C=\ncó nghĩa là một chương trình đã phát động một cuộc đảo chính. Đối thủ của nó, biết rằng nó được kêu gọi để phản ứng bởi số lượng chữ cái lẻ trên dòng, đã từ bỏ một Contessa. Một lần nữa, chương trình đầu tiên biết rằng đây là lần đầu tiên nó chưa hoàn thành trong lần gọi tiếp theo bởi số lượng ký tự chẵn trên dòng, vì vậy nó đã viết một dòng mới để kết thúc lượt của mình.

Eq~<\nsẽ có nghĩa là một chương trình đã cố gắng trao đổi ( E) và đối thủ của nó đã thách thức ( q). Chương trình Trao đổi tiết lộ rằng nó thực sự có một Đại sứ ( ~) và người thách thức đã từ bỏ một Thuyền trưởng như một hình phạt ( <). Sau khi kẻ thách thức thoát ra, chương trình Trao đổi được gọi lại với một chuỗi bốn ký tự làm đối số dòng lệnh thứ tư của nó (hoặc ba ký tự, nếu nó chỉ có một thẻ). Nó viết các ký tự đại diện cho các thẻ mà nó muốn giữ cho STDOUT và một dòng mới cho tệp.

Tq'\ncó nghĩa là một chương trình đã cố gắng đánh thuế không trung thực, bị thách thức và từ bỏ một Sát thủ. Nó minh họa trường hợp khác có hai ký tự được viết: nếu đến lượt bạn và bạn buộc phải từ bỏ một thẻ - từ thử thách chính xác của đối thủ (như ở đây) hoặc từ thử thách không chính xác của bạn về khối - thì bạn phải viết cả hai Thẻ bạn từ bỏ và một dòng mới để kết thúc lượt của bạn.

Asq!'\nsẽ có nghĩa là Người chơi B đã cố gắng ám sát người chơi A ( A), nhưng A tuyên bố có Contessa để chặn nó ( s). B không tin A và thách thức ( q). Một tiết lộ rằng trên thực tế, họ đã có một Contessa ( !). B đã từ bỏ một Assassin như một hình phạt, mất tiền của họ và kết thúc lượt của họ ( '\n), viết hai nhân vật như trong trường hợp đặc biệt đó. (Nếu A đã quyết định không để chặn hoặc thách thức, nó có thể đã được viết =, và sau đó đối thủ của nó sẽ thấy vui về nó đã kết thúc và viết một dòng mới. Điểm mấu sau đó đã có thể đọc A=\n, giống như ví dụ Coup.)

Sq*0\ncó nghĩa là một chương trình cố gắng ăn cắp; đối thủ thách đấu, không tin kẻ trộm có Thuyền trưởng; và chương trình ban đầu tiết lộ một Thuyền trưởng, vì vậy thử thách không thành công và người thách đấu từ bỏ Công tước như một hình phạt. (Một lựa chọn khác cho đối thủ của nó là chấp nhận Steal bằng cách viết p. Đối thủ của nó sau đó sẽ phát hiện kết thúc lượt của nó và viết \n, dẫn đến một dòng Sp\n.)

Trọng tài

Các chương trình sẽ được gọi bởi tập lệnh Python này. Nó tiến hành mười vòng, trong đó mọi đối thủ phải đối mặt với mọi đối thủ khác trong khi đi cả thứ nhất và thứ hai. Nó theo dõi số lượng thẻ và số xu và xác định người thua cuộc bằng chương trình đầu tiên kết thúc một dòng bằng dấu chấm hai lần. Các chương trình thoát với trạng thái khác không, sửa đổi tệp, viết di chuyển bất hợp pháp vào tệp hoặc cố gắng trao đổi bất hợp pháp sẽ tự động bị mất. Nếu mỗi người chơi thực hiện hơn 100 hành động, bao gồm các khối và thử thách, không có người chiến thắng, thì cả hai chương trình đều thua. Một người chiến thắng được cấp một điểm. Người chơi có chương trình ghi được nhiều điểm nhất sẽ thắng.

Tôi đề nghị bạn đọc mã nguồn của Trọng tài viên, đặc biệt là get_legal_actionschức năng. Nó có thể giúp bạn hiểu các đặc điểm kỹ thuật và viết chương trình của riêng bạn.

import itertools
import os
import random
import subprocess

class Player:
    def __init__(self, name, command):
        self.name = name
        self.command = command
        self.score = 0
        self.coins = 1
        self.cards = ""

actions_dict = {
    'E': '_', 'T': '0', 'A': "'", 'S': '<',
    'd': '0', 'a': '_', 'c': '<', 's': '='
}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {
    punishment_to_reveal[k]: k for k in punishment_to_reveal
}

def get_legal_actions(history, player, opponent):
    c = history[-1]
    result = ""
    # Our turn begins; choose an action.
    if c == '\n':
        if player.coins >= 10:
            return ["C"]
        ret = ['I\n'] + list("FET")
        if player.coins >= 3:
            ret.append("A")
        if player.coins >= 7:
            ret.append('C')
        if opponent.coins > 0:
            ret.append("S")
        return ret
    # Opponent attempted foreign aid; can pass or claim Duke to block.
    elif c == 'F':
        return list('dp')
    # We have been Couped; must surrender a card.
    elif c == 'C':
        return player.cards
    # We failed a challenge; must surrender a card and print a newline
    # if it is our turn.
    elif c in '~^*!$':
        if history[-3] in 'acds':
            return [card + '\n' for card in player.cards]
        return player.cards
    # Opponent attempted Exchange or Tax; can pass or challenge.
    elif c == 'E' or c == 'T':
        return list('pq')
    # Opponent attempted an Assassination; can block, challenge, or give in.
    elif c == 'A':
        return list('sq') + player.cards
    # Opponent attempted to Steal; can pass, block as Ambassador/Captain,
    # or challenge.
    elif c == 'S':
        return list('acpq')
    # Opponent blocked; can challenge or withdraw.
    elif c in 'acds':
        return list('q\n')
    # Opponent passed on blocking Foreign Aid/Tax/Exchange or they gave up a
    # card as punishment, must end turn.
    elif c in "p_'<=0":
        return ['\n']
    # Opponent challenged us.
    elif c == 'q':
        challenged_action = history[-2]
        # If we have the card they challenged us over, must reveal it.
        necessary_card = actions_dict[challenged_action]
        if necessary_card in player.cards:
            return [punishment_to_reveal[necessary_card]]
        # Otherwise, we can give up either of our cards, writing a newline
        # if it is our turn.
        if challenged_action in 'acds':
            return list(player.cards)
        else:
            return [card + '\n' for card in player.cards]
    else:
        return None

deck = ['_', "'", '<', '=', '0'] * 3
random.shuffle(deck)

def determine_turn_effects(line, output, cards, current_player, opponent):
    last_action = line[-2]
    # Only operate if the opponent declined to challenge (p) or the
    # program successfully challenged their block
    if last_action in "p_'<=0":
        primary_action = line[0]
        # Foreign Aid
        if primary_action == 'F':
            print current_player.name, "received 2 coins of Foreign Aid"
            current_player.coins += 2
        # Tax
        elif primary_action == 'T':
            print current_player.name, "received 3 coins of Tax"
            current_player.coins += 3
        # Steal
        elif primary_action == 'S':
            stolen_coins = 1 if opponent.coins == 1 else 2
            print current_player.name,\
                    "stole %d coins from %s" % (stolen_coins, opponent.name)
            current_player.coins += stolen_coins
            opponent.coins -= stolen_coins
        # Exchange, store desired cards and replace undesired ones
        elif primary_action == 'E':
            print current_player.name, "tried to take %r" % output, "from", cards
            legal_outputs = [''.join(p) for p in itertools.permutations(
                    cards, len(current_player.cards))]
            if output not in legal_outputs:
                print current_player.name, "forfeits by illegal exchange"
                return opponent
            current_player.cards = [
                reveal_to_punishment[c] for c in output
            ]
            undesired_cards = list(cards)
            for c in output:
                undesired_cards.remove(c)
            for card in undesired_cards:
                deck.append(reveal_to_punishment[card])
            random.shuffle(deck)
    # Coins are not returned from a successful Contessa block
    elif last_action == 's':
        print current_player.name, "lost 3 coins from a Contessa block"
        current_player.coins -= 3
    return None

def play_game(player1, player2, round_number, game_number):
    outfilename = os.path.abspath(__file__)[:-len(__file__)] + '_'.join([
        player1.name, player2.name, str(round_number), str(game_number)
    ]) + '.txt'
    print outfilename
    f = open(outfilename, 'w')
    f.close()
    players_list = [player1, player2]
    player1.cards = [deck.pop(), deck.pop()]
    player2.cards = [deck.pop(), deck.pop()]
    current_player_index = 0
    for i in range(200):
        current_player = players_list[current_player_index]
        opponent = players_list[(current_player_index+1) % 2]
        legal_actions = []
        original_contents = []
        original_contents_joined = ""
        with open(outfilename, 'r') as outfile:
            original_contents = outfile.readlines()
            original_contents_joined = ''.join(original_contents)
            if len(original_contents) == 0:
                legal_actions = ['I\n'] + list("FEST")
            else:
                legal_actions = get_legal_actions(
                        original_contents[-1], current_player, opponent)
        if not legal_actions:
            print "Error: file ended in invalid character"
            return current_player
        # Has the player completed an Exchange? Pass them new cards if so.
        exchange_cards = ""
        old_last_line = original_contents[-1] if len(original_contents) > 0 else '\n'
        if old_last_line[-1] != '\n' and old_last_line[0] == 'E' and \
                len(old_last_line) % 2 == 0 and old_last_line[-1] in "p_'<=0":
            exchange_cards = punishment_to_reveal[deck.pop()] + \
                    punishment_to_reveal[deck.pop()]

        cards = exchange_cards + ''.join(
                    punishment_to_reveal[card] for card in current_player.cards)
        args = current_player.command + [
            outfilename,
            str(opponent.coins),
            str(current_player.coins),
            cards
        ] + legal_actions
        print ' '.join(args)
        output = ""
        os.chdir(current_player.name)
        try:
            output = subprocess.check_output(args)
        # Competitors that fail to execute must forfeit
        except subprocess.CalledProcessError:
            print current_player.name, "forfeits by non-zero exit status"
            return opponent
        finally:
            os.chdir('..')

        new_contents = []
        new_contents_joined = ""
        with open(outfilename, 'r') as outfile:
            new_contents = outfile.readlines()
            new_contents_joined = ''.join(new_contents)
        if original_contents_joined != new_contents_joined[:-2] and \
                original_contents_joined != new_contents_joined[:-1]:
            print current_player.name, "forfeits by modifying the file"
            print "old:", original_contents
            print "new:", new_contents
            return opponent
        new_last_line = new_contents[-1]
        the_move_made = ""
        for action in legal_actions:
            if new_last_line.endswith(action):
                the_move_made = action
                break
        # Competitors that make an illegal move must forfeit
        if not the_move_made:
            print current_player.name, "forfeits with an illegal move,",\
                    "last line: %r" % new_last_line
            print opponent.name, "wins!"
            return opponent
        print current_player.name, "played %r" % the_move_made
        # Side effects of moves.
        #
        # Income, give the current player a coin.
        if the_move_made == "I\n":
            print current_player.name, "received 1 coin of income"
            current_player.coins += 1
        # The program surrendered a card on its turn; take it away. 
        elif len(the_move_made) == 2:
            print current_player.name, "lost a card from being challenged"
            current_player.cards.remove(the_move_made[0])
            # Coins are not returned from a successful Contessa block
            if new_last_line[-3] == '!':
                print current_player.name, "lost 3 coins from a Contessa block"
                current_player.coins -= 3
        # The program surrendered a card when it was not its turn.
        elif the_move_made in "_'<=0":
            print current_player.name, "gave up a", the_move_made
            current_player.cards.remove(the_move_made)
            if new_last_line[0] == 'C':
                opponent.coins -= 7
            elif new_last_line[0] == 'A':
                opponent.coins -= 3
            # Did the program unsuccessfully challenge an Assassination
            # (e.g. Aq^0\n)
            # or get caught falsely blocking with a Contessa
            # (e.g. Asq0\n)?
            # If yes, it loses right away.
            if new_last_line[0] == 'A' and new_last_line[1] in 'qs' and \
                    len(new_last_line) == 4:
                print current_player.name, "lost both cards in the same turn."
                print opponent.name, "wins!"
                return opponent
        elif the_move_made == 'S':
            print current_player.name, "attempted Steal"
        elif the_move_made == 'T':
            print current_player.name, "attempted Tax"
        elif the_move_made == 'A':
            print current_player.name, "attempted Assassinate"
        elif the_move_made == 'C':
            print current_player.name, "launched a Coup"
        elif the_move_made == 'F':
            print current_player.name, "attempted Foreign Aid"
        elif the_move_made == 'E':
            print current_player.name, "attempted Exchange"
        elif the_move_made == 'q':
            print current_player.name, "challenged"
        elif the_move_made == 'p':
            print current_player.name, "passed"
        elif the_move_made == 'a':
            print current_player.name, "blocked with an Ambassador"
        elif the_move_made == 'c':
            print current_player.name, "blocked with a Captain"
        elif the_move_made == 's':
            print current_player.name, "blocked with a Contessa"
        elif the_move_made == 'd':
            print current_player.name, "blocked with a Duke"
        # The program revealed a card from an opponent's unsuccessful challenge.
        # Give it a new card.
        # Special case: a program whose Exchange is unsuccessfully challenged
        # may keep the Ambassador it revealed in the Exchange, so give a new
        # card for a revealed Ambassador only if it was used to block a Steal.
        elif the_move_made in '^*!$' or (the_move_made == '~' and
                new_last_line[0] == 'S'):
            p = reveal_to_punishment[the_move_made]
            current_player.cards.remove(p)
            current_player.cards.append(deck.pop())
            deck.append(p)
            random.shuffle(deck)
            print current_player.name, "did have a", the_move_made
        # The program ended its turn. We must examine the rest of the line to
        # determine the side effects.
        elif the_move_made == '\n':
            potential_winner = determine_turn_effects(
                    new_last_line, output.strip(), cards, current_player,
                    opponent)
            if potential_winner:
                print potential_winner.name,\
                        "wins because their opponent made an illegal exchange!"
                return potential_winner

        # One player has lost all their cards. Victory for the opponent!
        if current_player.cards == []:
            print opponent.name, "wins by eliminating both opponent cards!"
            return opponent

        current_player_index += 1
        current_player_index %= 2
    return None

competitors = []
competitors.append(Player("Challenger", ["./challenger"]))
competitors.append(Player("Random", ["./random"]))
# ...More competitors here

for i in range(10):
    print "-- Round", i
    j = 0
    for pairing in itertools.permutations(competitors, 2):
        player1, player2 = pairing
        print '--- Game', j, ':', player1.name, 'vs.', player2.name
        winner = play_game(player1, player2, i, j)
        if not winner:
            j += 1
            continue
        winner.score += 1
        player1.coins = 1
        player1.cards = ""
        player2.coins = 1
        player2.cards = ""
        deck = ['_', "'", '<', '=', '0'] * 3
        random.shuffle(deck)
        j += 1

competitors.sort(reverse=True, key=lambda player: player.score)

for player in competitors:
    print '%5d %s' % (player.score, player.name)

Điều khoản khác

Một chương trình không thể có mã cụ thể cho chương trình khác và các chương trình không thể giúp đỡ lẫn nhau. (Bạn có thể có nhiều chương trình, nhưng chúng không thể tương tác với nhau theo bất kỳ cách nào.)

Nếu chương trình của bạn mất cả hai thẻ trong cùng một lượt, nó chỉ cần viết một thẻ. Trọng tài sẽ phát hiện ra rằng nó đã bị loại bỏ.

Có thể và khuyến khích, nhưng không bắt buộc, đối với các chương trình kiểm tra lịch sử của trò chơi trong tệp. Bằng cách đó, họ có thể xác định được những quân bài mà đối thủ của họ đã tuyên bố có và bắt họ nói dối.

Trong trò chơi Coup thực sự, bạn có thể thách đấu một hành động và sau đó cố gắng chặn nó trong cùng một lượt. Tôi không thể làm cho đặc tả hoạt động nếu tôi cho phép điều đó, vì vậy bạn có thể thách thức hoặc chặn một hành động nhất định, nhưng không phải cả hai.

Tôi xin lỗi @PeterTaylor, người mà lần trước tôi đã đăng bài này đề nghị tôi đăng nó lên hộp cát và làm lại giao thức để đầu ra đường ống qua lại trong STDOUT / STDIN. Tôi đã cố gắng rất nhiều để thực hiện công việc đó, dành trọn một ngày cho nó (khi tôi đã dành trọn một ngày để viết thử thách ban đầu). Nhưng Exchanges tỏ ra rất phức tạp khi thực hiện theo cách đó, cộng với việc nó sẽ làm tăng sự phức tạp của việc gửi bằng cách yêu cầu họ theo dõi số lượng xu của chính họ. Vì vậy, tôi đã đăng thử thách ít nhiều như ban đầu.


Tôi hoàn toàn không hiểu làm thế nào một lượt đã kết thúc. Từ bài đăng, một thử thách / khối thành công sẽ kết thúc lượt chơi. Còn những người khác thì sao? Có thể một số người trao đổi vô hạn lần lượt miễn là đối thủ không thách đấu?
tsh

@tsh Một chương trình luôn kết thúc lượt của mình bằng cách viết một dòng mới, nhưng nó có thể viết một ký tự trước đó nếu nó mất Thu nhập hoặc mất thẻ trong lượt của chính nó. Một thử thách / khối thành công thực sự sẽ kết thúc lượt chơi. Một khối Steal thành công sẽ đi: chương trình A viết S, chương trình khối B bằng cách viết c, A từ chối thách thức bằng cách viết \n. Thử thách thành công của Steal sẽ diễn ra: A viết S, B thách thức bằng cách viết q, A thừa nhận thử thách bằng cách viết _\n, ví dụ: Bạn chỉ có thể thực hiện một hành động mỗi lượt, bao gồm Trao đổi. Các phản ứng pháp lý đối với Exchange là vượt qua và thách thức.
Tím P

2
@jaaq Tôi chưa quyết định thời hạn. Tôi ít nhất sẽ giữ nó mở cho đến khi bạn gửi :)
Purple P

1
@jaaq Arbiter tiến hành 10 vòng c P2 phù hợp với nhau, trong đó c là số lượng đối thủ cạnh tranh. Hiện tại có 13 đối thủ, kết quả là 10 (13P2) = 10 (13! / 11!) = 10 (13 * 12) = 1560 trận đấu.
Tím P

1
@jaaq Mình đi vắng. Tôi đã trở lại. Cập nhật.
Tím P

Câu trả lời:


4

Máy tính

Lập kế hoạch cho loạt chiến thắng của anh ta, và thách thức bất cứ điều gì có thể ngăn anh ta chiến thắng.

from __future__ import division
import sys
import random
import operator

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=', '0']

statefilename = './state.txt'
flags = set()
# Flags:
# 1 We went first
# $ Attacking with Duke
# * Attacking with Captain
# ^ Attacking with Assassin
# d Opponent used Duke
# c Opponent used Captain
# A Opponent used Assassin
# F Opponent used Foreign Aid

with open(statefilename, "a+") as statefile:
    statefile.seek(0)
    if statefile.readline().strip() == filename:
        flags = set(statefile.readline().strip())

with open(filename, "r+") as history:
    line = "\n"
    turn = 0
    oppcardcount = 4 - len(mycards)
    for a in history:
        line = a
        turn += 1
        if [c for c in line if c in lossActions]:
            oppcardcount -= 1
    else:
        flags.add("1")

    mycoins = int(mycoins)
    othercoins = int(othercoins)
    mycardcount = len(mycards)

    if line == 'T':
        othercoins += 3
        flags.add('d')
    elif line == 'S':
        othercoins += (2 if mycoins > 2 else mycoins)
        mycoins -= (2 if mycoins > 2 else mycoins)
        flags.add('c')
    elif line == 'A':
        othercoins -= 3
        mycardcount -= 1
        flags.add('A')
    elif line == 'F':
        flags.add('F')
    elif line == 'I\n':
        # If opponent is backing down, they're not so scary anymore
        flags.discard('d')
        flags.discard('c')
        flags.discard('F')

    # What's the least aggressive play that still wins?
    iGetStolen = ('c' in flags and not '*' in mycards and not '~' in mycards)
    iGetAssassinated = ('A' in flags and not '!' in mycards)
    incomeTimeToWin = max(0,7*oppcardcount-mycoins)+oppcardcount if not iGetStolen else 1000
    faidTimeToWin = max(0,7*oppcardcount-mycoins+1)//2+oppcardcount if not iGetStolen else 1000
    dukeTimeToWin = max(0,7*oppcardcount+(2*(oppcardcount-mycardcount) if iGetStolen else 0)-mycoins+2)//(3 if not iGetStolen else 1)+oppcardcount
    assassinTimeToWin = max(0,3*oppcardcount-mycoins)+oppcardcount if not iGetStolen else oppcardcount if mycoins >= 5*oppcardcount-2 else 1000
    captainTimeToWin = max(0,7*oppcardcount-mycoins+1)//2+oppcardcount
    faidAssassinTimeToWin = max(0,3*oppcardcount-mycoins+1)//2+oppcardcount if not iGetStolen else 1000
    dukeAssassinTimeToWin = max(0,3*oppcardcount+(2*(oppcardcount-mycardcount) if iGetStolen else 0)-mycoins+2)//(3 if not iGetStolen else 1)+oppcardcount
    captainAssassinTimeToWin = max(0,3*oppcardcount-mycoins+1)//2+oppcardcount
    opponentMoneySpeed = (2 if iGetStolen else 3 if 'd' in flags else 2 if 'F' in flags and not '$' in mycards else 1)
    opponentTimeToWin = max(0,(3 if iGetAssassinated else 7)*mycardcount-othercoins+opponentMoneySpeed-1)//opponentMoneySpeed+mycardcount
    opponentTimeToWinCaptained = max(0,(3 if iGetAssassinated else 7)*mycardcount+2*(mycardcount-oppcardcount)-(othercoins-2 if othercoins>2 else 0)+opponentMoneySpeed-3)//(opponentMoneySpeed-2)+mycardcount if opponentMoneySpeed > 2 else 1000

    def pickCardToLose():
        favoriteCards = []
        if dukeTimeToWin < opponentTimeToWin and '$' in mycards:
            favoriteCards = ['$', '!', '*', '~', '^']
        elif dukeAssassinTimeToWin < opponentTimeToWin and ('$' in mycards or '$' in flags) and '^' in mycards:
            favoriteCards = ['^', '$', '!', '*', '~']
        elif assassinTimeToWin < opponentTimeToWin and '^' in mycards:
            favoriteCards = ['^', '!', '*', '~', '$']
        elif captainTimeToWin < opponentTimeToWinCaptained and '*' in mycards:
            favoriteCards = ['*', '!', '$', '^', '~']
        elif faidTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
            favoriteCards = ['!', '*', '~', '$', '^']
        elif faidAssassinTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
            favoriteCards = ['^', '!', '*', '~', '$']
        elif captainAssassinTimeToWin < opponentTimeToWinCaptained and '*' in mycards and '^' in mycards:
            favoriteCards = ['^', '*', '!', '$', '~']
        else:
            favoriteCards = ['!', '*', '~', '$', '^']
        # Losing a card.  Decide which is most valuable.
        for k in favoriteCards:
            if k in mycards:
                cardToLose = k
        return reveal_to_punishment[cardToLose]

    action = legalActions[0]
    if line == "\n":
        # First turn behavior
        if '$' in mycards and 'T' in legalActions:
            action = 'T'
            flags.add('$')
        elif '*' in mycards and 'S' in legalActions:
            action = 'S'
            flags.add('*')
        elif '^' in mycards and 'I\n' in legalActions:
            action = 'I\n'
            flags.add('^')
        elif '~' in mycards and 'E' in legalActions:
            action = 'E'
        elif 'T' in legalActions:
            # Contessa/Contessa?  Need to lie.
            action = 'T'
            flags.add('$')
    elif set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
        # This might change our strategy
        flags.discard(action)
    elif '$' in mycards and 'd' in legalActions:
        action = 'd'
    elif '~' in mycards and 'a' in legalActions:
        action = 'a'
    elif '*' in mycards and 'c' in legalActions:
        action = 'c'
    elif '!' in mycards and 's' in legalActions:
        action = 's'
    elif 'q' in legalActions and line[-1] in 'dacs':
        # We're committed at this point
        action = 'q'
    elif 'q' in legalActions and '*' in flags and line[-1] in 'SE':
        # Don't allow these when using a steal strategy
        action = 'q'
    elif 'q' in legalActions and turn == 1:
        if line == 'T':
            if mycards == '$$' or mycards == '^^' or mycards == '!!':
                action = 'q'
            else:
                action = 'p'
                flags.add('d')
        elif line == 'S':
            if '$' in mycards and '^' in mycards:
                action = 'p'
                flags.add('c')
            else:
                action = 'q'
        elif line == 'E':
            action = 'p'
    elif line == 'A' and len(mycards) > 1:
        # Don't challenge the first assasination.  We'll get 'em later.
        action = pickCardToLose()
        flags.add('A')
    elif line == 'A':
        # Can't let this pass
        action = 'q'
    elif line == 'C':
        # Taking damage
        action = pickCardToLose()
    elif len(line) == 2 and line[1] == 'q':
        # My base action was successfully challenged
        action = pickCardToLose()+"\n"
        # Also stop claiming what we were challenged for
        if line == "Tq":
            flags.discard('$')
        elif line == "Sq":
            flags.discard('*')
        elif line == "Aq":
            flags.discard('^')
    elif len(line) == 3 and line[1] == 'q':
        # I failed challenging a base action
        action = pickCardToLose()
    elif len(line) == 3 and line[2] == 'q':
        # My block was successfully challenged
        action = pickCardToLose()
    elif len(line) == 4 and line[2] == 'q':
        # I failed challenging a block
        action = pickCardToLose()+"\n"
    else:
        if 'p' in legalActions:
            # Default to pass if no other action is chosen
            action = 'p'

        if dukeTimeToWin <= opponentTimeToWin and ('$' in mycards or '$' in flags):
            if 'C' in legalActions:
                action = 'C'
            elif 'T' in legalActions:
                action = 'T'
        elif incomeTimeToWin <= opponentTimeToWin:
            if 'C' in legalActions:
                action = 'C'
            elif 'I\n' in legalActions:
                action = "I\n"
        elif dukeAssassinTimeToWin <= opponentTimeToWin and ('$' in mycards or '$' in flags) and '^' in mycards and mycardcount > 1:
            if 3*oppcardcount <= mycoins - (2*(oppcardcount-1) if iGetStolen else 0) and 'A' in legalActions:
                action = 'A'
            elif 'T' in legalActions:
                action = 'T'
            flags.add('^');
        elif assassinTimeToWin <= opponentTimeToWin and '^' in mycards:
            if 'A' in legalActions:
                action = 'A'
            elif 'I\n' in legalActions:
                action = 'I\n'
            flags.add('^');
        elif captainTimeToWin <= opponentTimeToWinCaptained and '*' in mycards:
            if 'C' in legalActions:
                action = 'C'
            elif 'S' in legalActions:
                action = 'S'
            elif 'I\n' in legalActions:
                action = 'I\n'
            flags.add('*');
        elif faidTimeToWin <= opponentTimeToWin and not 'd' in flags:
            if 'C' in legalActions:
                action = 'C'
            elif 'F' in legalActions:
                action = 'F'
        elif faidAssassinTimeToWin <= opponentTimeToWin and '^' in mycards and not 'd' in flags:
            if 'A' in legalActions:
                action = 'A'
            elif 'F' in legalActions:
                action = 'F'
            flags.add('^');
        elif captainAssassinTimeToWin <= opponentTimeToWinCaptained and '*' in mycards and '^' in mycards:
            if 'A' in legalActions:
                action = 'A'
            elif 'S' in legalActions:
                action = 'S'
            flags.add('^');
            flags.add('*');
        elif 'q' in legalActions:
            action = 'q'
        # No winning strategy.  Find something useful to do anyway.
        elif 'C' in legalActions and not '^' in flags:
            action = 'C'
        elif 'S' in legalActions and '*' in flags:
            action = 'S'
        elif 'A' in legalActions and '^' in flags:
            action = 'A'
        elif 'E' in legalActions and '~' in mycards and dukeAssassinTimeToWin < opponentTimeToWin:
            action = 'E'
        elif 'F' in legalActions and not 'd' in flags:
            action = 'F'
        elif 'T' in legalActions:
            action = 'T'
            flags.add('$');
    if action == 'q':
        if line == 'T' or line == 'Fd':
            flags.discard('d')
        elif line == 'S' or line == 'Sc':
            flags.discard('c')
        elif line == 'A':
            flags.discard('A')
    history.write(action)

if len(mycards) > 2:
    favoriteCards = []
    if dukeTimeToWin < opponentTimeToWin and '$' in mycards:
        favoriteCards = ['$', '!', '*', '~', '^']
    elif dukeAssassinTimeToWin < opponentTimeToWin and ('$' in mycards or '$' in flags) and '^' in mycards:
        favoriteCards = ['^', '$', '!', '*', '~']
    elif assassinTimeToWin < opponentTimeToWin and '^' in mycards:
        favoriteCards = ['^', '!', '*', '~', '$']
    elif captainTimeToWin < opponentTimeToWinCaptained and '*' in mycards:
        favoriteCards = ['*', '!', '$', '^', '~']
    elif faidTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
        favoriteCards = ['!', '*', '~', '$', '^']
    elif faidAssassinTimeToWin < opponentTimeToWin and '^' in mycards and not 'd' in flags:
        favoriteCards = ['^', '!', '*', '~', '$']
    elif captainAssassinTimeToWin < opponentTimeToWinCaptained and '*' in mycards and '^' in mycards:
        favoriteCards = ['^', '*', '!', '$', '~']
    else:
        favoriteCards = ['!', '*', '~', '$', '^']
    # Losing two cards.  Decide which is most valuable.
    possibleCards = [k for k in favoriteCards if k in mycards]
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

with open(statefilename, "w") as statefile:
    statefile.write(filename+"\n")
    statefile.write(''.join(list(flags))+"\n")

Áo khoác

Nói sự thật lúc đầu, nhưng bắt đầu nói dối khi nó ngừng bị sứt mẻ. Cũng có một số hành vi giải quyết. (Một cách gần đúng về cách tôi cư xử khi chơi trò chơi này với con người)

import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['C', '~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=' '0']

statefilename = './state.txt'
myclaims = set()
otherclaims = set()
mycaughtlies = set()
othercaughtlies = set()
flags = set()
# Flags:
# * Opponent had a chance to challenge us just now
# & Opponent has stopped wildly challenging everything
# E We have exchanged at least once
# S Opponent did not block a steal.  Go for the jugular!
# _ Opponent has lost a card

with open(statefilename, "a+") as statefile:
    statefile.seek(0)
    if statefile.readline().strip() == filename:
        myclaims = set(statefile.readline().strip())
        otherclaims = set(statefile.readline().strip())
        mycaughtlies = set(statefile.readline().strip())
        othercaughtlies = set(statefile.readline().strip())
        flags = set(statefile.readline().strip())

def getFavoriteCards():
    favoriteCards = []
    if '*' in otherclaims:
        favoriteCards.append('~')
    elif not '~' in otherclaims:
        favoriteCards.append('*')
    if len(otherclaims) > (0 if '_' in flags else 1) and mycoins > 1 and not '!' in otherclaims:
        favoriteCards.append('^')
    favoriteCards.append('!')
    favoriteCards.append('$')
    if not '~' in favoriteCards:
        favoriteCards.append('~')
    return favoriteCards

def pickCardToLose():
    # Losing a card.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    cardToLose = ''
    for k in favoriteCards:
        if k in mycards:
            cardToLose = k
    for k in mycards:
        if not k in favoriteCards:
            cardToLose = k
    return reveal_to_punishment[cardToLose]

with open(filename, "r+") as history:
    line = "\n"
    for a in history:
        line = a
    if 'q' in legalActions:
        otherclaims.add(punishment_to_reveal[actions_dict[line[-1]]])
    if len(line) > 2 and line.endswith('\n') and line[-2] in lossActions:
        otherclaims.discard(punishment_to_reveal[line[-2]])
        flags.add('_')
    if len(line) > 2 and line.endswith('\n') and (line.startswith('Ep') or line.startswith('Eq~')):
        othercaughtlies = set()
    if '*' in flags:
        flags.discard('*')
        if line[-1] not in 'qdacs':
            flags.add('&')
            if line[-2] == 'F':
                othercaughtlies.add('$')
            if line[-2] == 'S':
                othercaughtlies.add('*')
                othercaughtlies.add('~')
            if line[-2] == 'A':
                othercaughtlies.add('!')
    action = legalActions[0]
    if set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
        if action in reveal_to_punishment:
            myclaims.discard(action)
    elif '&' in flags:
        preferredActions = []
        mysafecards = myclaims.union(mycards)

        # Calculate the financial situation
        mygain = 0
        oppgain = 0
        if '*' in mysafecards and not '*' in otherclaims and not '~' in otherclaims:
            mygain += 2
            oppgain -= 2
        elif '$' in mysafecards:
            mygain += 3
        elif not '$' in otherclaims:
            mygain += 1 # This script doesn't use foreign aid
        else:
            mygain += 1
        if '*' in otherclaims and not '*' in mysafecards and not '~' in mysafecards:
            oppgain += 2
            mygain -= 2
        elif '$' in mysafecards:
            oppgain += 3
        elif not '$' in otherclaims:
            oppgain += 2
        else:
            oppgain += 1
        mydist = 7 - int(mycoins)
        oppdist = 7 - int(othercoins)
        if '^' in mysafecards and len(otherclaims) > (0 if '_' in flags else 1) and not '!' in otherclaims:
            mydist -= 4
        if '^' in otherclaims and not '!' in mysafecards:
            oppdist -= 4
        if mydist > 0 and (oppdist <= 0 or mygain <= 0 or (oppgain > 0 and ((oppdist+oppgain-1) // oppgain) < ((mydist+mygain-1) // mygain))):
            # Not winning.  Do something desperate.
            timeToLive = ((oppdist+oppgain-1) // oppgain) if oppdist > 0 else 0
            favoriteCards = getFavoriteCards()
            if timeToLive < len(otherclaims):
                preferredActions.append('q')
            if (timeToLive or len(mycards) > 1) and favoriteCards[0] not in mysafecards:
                preferredActions.append('E')
            elif mycoins >= 3 and random.randint(0,2):
                preferredActions.append('A')
            else:
                preferredActions.append('S')

        preferredActions.append('s')
        if 'a' in legalActions and ('~' in mycards or '*' in mycards) and not 's' in flags:
            # Allow the first steal, as bait
            preferredActions.append('p')
            flags.add('s')
            if '~' in mycards:
                flags.discard('E')
        if '$' in mysafecards:
            preferredActions.append('d')
        if '~' in mysafecards:
            preferredActions.append('a')
        elif '*' in mysafecards:
            preferredActions.append('c')
        else:
            preferredActions.append('c' if random.randint(0,1) else 'a')
        if not 'E' in flags:
            preferredActions.append('E')
        if not ('~' in otherclaims or '*' in otherclaims):
            preferredActions.append('S')
        if len(otherclaims) > (0 if '_' in flags else 1) and ('^' in mycards or not '_' in flags) and not '!' in otherclaims:
            preferredActions.append('A')
        preferredActions.append('T')
        if line[-1] in actions_dict and punishment_to_reveal[actions_dict[line[-1]]] in othercaughtlies:
            preferredActions.append('q')
        preferredActions += ['p', '\n']
        if len(myclaims) < len(mycards):
            # Slip a lie in before admitting all cards in hand
            preferredActions = [a for a in preferredActions
                if not a in actions_dict
                or not punishment_to_reveal[actions_dict[a]] in mysafecards]
        else:
            preferredActions = [a for a in preferredActions
                if not a in actions_dict
                or punishment_to_reveal[actions_dict[a]] in mycards
                or not punishment_to_reveal[actions_dict[a]] in mycaughtlies]
        preferredActions = [a for a in preferredActions if a in legalActions]
        if preferredActions:
            action = preferredActions[0]
        else:
            loss = pickCardToLose()
            if loss in legalActions:
                action = loss
            elif loss+"\n" in legalActions:
                action = loss+"\n"
    else:
        preferredActions = []
        if not ('~' in otherclaims or '*' in otherclaims):
            preferredActions.append('S')
        preferredActions += ['T', 'E', 'd', 'a', 'c', 's', 'p', '\n']
        if not '!' in otherclaims:
            preferredActions.append('A')
        preferredActions = [a for a in preferredActions if a in legalActions]
        # Filter out lies, provided that doesn't filter out everything
        preferredActions = [a for a in preferredActions
            if not a in actions_dict
            or punishment_to_reveal[actions_dict[a]] in mycards
        ] or [a for a in preferredActions
            if not a in actions_dict
            or not punishment_to_reveal[actions_dict[a]] in mycaughtlies
        ]
        if preferredActions:
            action = preferredActions[0]
        else:
            loss = pickCardToLose()
            if loss in legalActions:
                action = loss
            elif loss+"\n" in legalActions:
                action = loss+"\n"
        if 'a' in legalActions:
            if action not in 'acq':
                # If vulnerable to stealing, don't admit it!
                action = random.choice('acq')
            elif not 's' in flags:
                # Allow the first steal, as bait
                action = 'p'
                flags.add('s')
                if '~' in mycards:
                    flags.discard('E')
    if action.strip("\n") in lossActions:
        myclaims.discard(punishment_to_reveal[action.strip("\n")])
        if line[-1] == 'q':
            # Also stop claiming what we were challenged for
            myclaims.discard(punishment_to_reveal[actions_dict[line[-2]]])
            mycaughtlies.add(punishment_to_reveal[actions_dict[line[-2]]])
    if action == 'q':
        # We challenged it.  One way or another, they will not have this card later.
        otherclaims.discard(punishment_to_reveal[actions_dict[line[-1]]])
        othercaughtlies.add(punishment_to_reveal[actions_dict[line[-1]]])
    if action in actions_dict:
        myclaims.add(punishment_to_reveal[actions_dict[action]])
        flags.add('*')
    history.write(action)

if len(mycards) > 2:
    flags.add('E')
    mycaughtlies = set()
    # Losing two cards.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    # After an exchange, we can claim what we like.  Throw in some lying for more flexibility.
    myclaims = set()
    possibleCards = [k for k in favoriteCards if k in mycards]
    if random.randint(1,len(possibleCards)) > len(mycards) - 2:
        myclaims.add(possibleCards[0])
        possibleCards = possibleCards[1:]
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

with open(statefilename, "w") as statefile:
    statefile.write(filename+"\n")
    statefile.write(''.join(list(myclaims))+"\n")
    statefile.write(''.join(list(otherclaims))+"\n")
    statefile.write(''.join(list(mycaughtlies))+"\n")
    statefile.write(''.join(list(othercaughtlies))+"\n")
    statefile.write(''.join(list(flags))+"\n")

Tên cướp

Cố gắng để thoát khỏi Đại sứ và Thuyền trưởng của đối thủ, và giành chiến thắng bằng cách ăn cắp.

import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['C', '~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=' '0']

def getFavoriteCards():
    return ['*', '!', '~', '$', '^']

def pickCardToLose():
    # Losing a card.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    cardToLose = ''
    for k in favoriteCards:
        if k in mycards:
            cardToLose = k
    for k in mycards:
        if not k in favoriteCards:
            cardToLose = k
    return reveal_to_punishment[cardToLose]

with open(filename, "r+") as history:
    line = "\n"
    turn = 0
    for a in history:
        line = a
        turn += 1
    action = legalActions[0]
    if set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
    elif 'p' in legalActions and turn == 1 and line == "E":
        # Let this pass... once
        action = 'p'
    elif 'q' in legalActions and line[-1] in 'SEac':
        # These get in the way of stealing, get rid of them even if it costs us a card
        action = 'q'
    elif 'E' in legalActions and '~' in mycards and '*' not in mycards:
        action = 'E'
    elif 'S' in legalActions:
        action = 'S'
    elif 's' in legalActions:
        if '!' in mycards:
            action = 's'
        elif len(mycards) == 1:
            action = random.choice('sq')
        else:
            action = pickCardToLose()
    elif 'p' in legalActions:
        action = 'p'
    elif line == 'A' or line == 'C':
        # Taking damage
        action = pickCardToLose()
    elif len(line) == 2 and line[1] == 'q':
        # My base action was successfully challenged
        action = pickCardToLose()+"\n"
    elif len(line) == 3 and line[1] == 'q':
        # I failed challenging a base action
        action = pickCardToLose()
    elif len(line) == 3 and line[2] == 'q':
        # My block was successfully challenged
        action = pickCardToLose()
    elif len(line) == 4 and line[2] == 'q':
        # I failed challenging a block
        action = pickCardToLose()+"\n"
    history.write(action)

if len(mycards) > 2:
    # Losing two cards.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    possibleCards = [k for k in favoriteCards if k in mycards]
    if mycards.count('*') > 1:
        # Hooray captains!
        possibleCards = ['*'] + possibleCards
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

Giết người đẫm máu

Là một đối trọng với Bandit, phần này đi sâu vào chiến lược Duke + Assassin.

import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legalActions = sys.argv[5:]

actions_dict = {'E': '_', 'T': '0', 'A': "'", 'S': '<', 'd': '0', 'a': '_', 'c': '<', 's': '='}
punishment_to_reveal = {'_': '~', "'": '^', '<': '*', '=': '!', '0': '$'}
reveal_to_punishment = {punishment_to_reveal[k]: k for k in punishment_to_reveal}

obviousActions = ['C', '~', '^', '*', '!', '$']
lossActions = ['_', "'", '<', '=' '0']

def getFavoriteCards():
    return ['^', '$', '!', '*', '~']

def pickCardToLose():
    # Losing a card.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    cardToLose = ''
    for k in favoriteCards:
        if k in mycards:
            cardToLose = k
    for k in mycards:
        if not k in favoriteCards:
            cardToLose = k
    return reveal_to_punishment[cardToLose]

with open(filename, "r+") as history:
    line = "\n"
    stealHappened = 0
    oppcardcount = 4 - len(mycards)
    for a in history:
        line = a
        if line[0] == 'S':
            stealHappened = 1
        if [c for c in line if c in lossActions]:
            oppcardcount -= 1
    action = legalActions[0]
    if set(obviousActions).intersection(legalActions):
        # Always take these actions if possible
        for a in set(obviousActions).intersection(legalActions):
            action = a
    elif 'q' in legalActions and line[-1] in 's':
        # We need this gone
        action = 'q'
    elif 'E' in legalActions and '~' in mycards:
        action = 'E'
    elif 'A' in legalActions and (len(mycards) == 1 or mycoins >= 3*oppcardcount+(2 if stealHappened and oppcardcount>1 else 0)):
        action = 'A'
    elif 'T' in legalActions:
        action = 'T'
    elif 'd' in legalActions:
        action = 'd'
    elif 'c' in legalActions and '*' in mycards:
        action = 'c'
    elif 'a' in legalActions and '~' in mycards:
        action = 'a'
    elif 's' in legalActions:
        if '!' in mycards:
            action = 's'
        elif len(mycards) == 1:
            action = random.choice('sq')
        else:
            action = pickCardToLose()
    elif 'p' in legalActions:
        action = 'p'
    elif line == 'A' or line == 'C':
        # Taking damage
        action = pickCardToLose()
    elif len(line) == 2 and line[1] == 'q':
        # My base action was successfully challenged
        action = pickCardToLose()+"\n"
    elif len(line) == 3 and line[1] == 'q':
        # I failed challenging a base action
        action = pickCardToLose()
    elif len(line) == 3 and line[2] == 'q':
        # My block was successfully challenged
        action = pickCardToLose()
    elif len(line) == 4 and line[2] == 'q':
        # I failed challenging a block
        action = pickCardToLose()+"\n"
    history.write(action)

if len(mycards) > 2:
    # Losing two cards.  Decide which is most valuable.
    favoriteCards = getFavoriteCards()
    possibleCards = [k for k in favoriteCards if k in mycards]
    if mycards.count('^') > 1:
        # Hooray assassins!
        possibleCards = ['^'] + possibleCards
    if len(possibleCards) < len(mycards) - 2:
        possibleCards = list(mycards)
        random.shuffle(possibleCards)
    mycards = ''.join(possibleCards[:(len(mycards)-2)])
    print mycards

Tất cả được thêm vào bảng xếp hạng, và làm khá tốt! Tôi có thể đề nghị đổi tên Betrayer thành Turncoat không? Làm cho nó kịch tính hơn một chút :)
Purple P

@PurpleP Đổi tên! "Kẻ phản bội" là một lựa chọn vội vàng; Nó thực sự được đặt theo tên của tôi trong quá trình phát triển, nhưng điều đó dường như không đúng khi tôi có nhiều thí sinh.
Brilliand

Máy tính đã được thêm vào bảng xếp hạng.
Tím P

1
Xin chúc mừng, Máy tính là Vua của Đồi!
Tím P

4

Người giải quyết

Người giải quyết cố gắng nhớ những lá bài nào được chơi trước đó và những bước di chuyển trước đó của đối thủ.

đây là phiên bản thứ 2 chưa hoàn thành (và bây giờ nó là một mớ hỗn độn lớn)

để làm cho nó hoạt động trên nút 10 thêm competitors.append(Player("Solver", ["node", "--experimental-modules", "./solver.mjs"]))

nếu nút 12 competitors.append(Player("Solver", ["node", "./solver.js"]))

hãy cẩn thận với loại tập tin

import  fs from 'fs'
import { promisify } from 'util'

const appendFile = promisify(fs.appendFile)
const writeFile = promisify(fs.writeFile)
const readFile = promisify(fs.readFile)

const delay = ms => new Promise(_ => setTimeout(_, ms));

let [filename, othercoins, mycoins, mycards ] = process.argv.slice(2)
othercoins = +othercoins
mycoins = +mycoins

const move = async m => await appendFile(filename, m)
const message = m => process.stdout.write(m)
const endTurn = async _ => await move(`\n`) 

const stateFileName = `./state.json`

const defaultState = {
    inTheDeck: [],
    oponentCards: [],
    oponentMissingTempCard: "",
    oponentMissingCards: [],
    oponentDropedCards: [],
    oponentCardModifier: 0
}

const CardTypes = Object.freeze({
    Ambassador : `Ambassador`,
    Assassin : `Assassin`,
    Captain  : `Captain`,
    Contessa : `Contessa`,
    Duke     : `Duke`,
})

const revealTable = Object.freeze({
    [CardTypes.Ambassador]: `~`,
    [CardTypes.Assassin]: `^`,
    [CardTypes.Captain]: `*`,
    [CardTypes.Contessa]: `!`,
    [CardTypes.Duke]: `$`,
})

const giveUpTable = Object.freeze({
    [CardTypes.Ambassador]: `_`,
    [CardTypes.Assassin]: `'`,
    [CardTypes.Captain]: `<`,
    [CardTypes.Contessa]: `=`,
    [CardTypes.Duke]: `0`,
})

function GetRevealCardChar(cardType) {
    return revealTable[cardType]
}

function GetRevealCardType(char) {
    return Object.keys(revealTable).find(key => revealTable[key] === char)
}

function GetGiveUpCardChar(cardType) {
    return giveUpTable[cardType]
}

function GetGiveUpCardType(char) {
    return Object.keys(giveUpTable).find(key => giveUpTable[key] === char)
}

async function GiveUpCard(cardType, endTurn = false) {
    return await move(
        GetGiveUpCardChar(cardType) + `${endTurn?`\n`:``}`
    );
}

function OponentCanHave(cardType) {
    // it has it
    if (!!~state.oponentCards.indexOf(cardType)) return true

    if (state.oponentCards.length + state.oponentDropedCards.length >= 2) return false

    return true
}


function GiveCard(getOrder = false) {
    // TODO: Tactic
    const giveAwayOrder = [
        CardTypes.Captain,
        CardTypes.Ambassador,
        CardTypes.Contessa,
        CardTypes.Assassin,
        CardTypes.Duke,
    ]

    const tmp =  mycards
        .split('')
        .map(GetRevealCardType)

    let [unique, duplicate] = tmp.reduce(([unique, duplicate], item) => {
        return unique.includes(item) ? 
            [unique, [...duplicate, item]] :
            [[...unique, item], duplicate]
    }
    , [[],[]])

    unique.sort(
        (a, b) => giveAwayOrder.indexOf(a) - giveAwayOrder.indexOf(b));
    duplicate.sort(
        (a, b) => giveAwayOrder.indexOf(a) - giveAwayOrder.indexOf(b))

    const out = [...duplicate, ...unique]

    return getOrder? out: GetGiveUpCardChar(out[0]);
}

const iHaveAmbassador = !!~mycards.indexOf(`~`)
const iHaveAssassin = !!~mycards.indexOf(`^`)
const iHaveCaptain = !!~mycards.indexOf(`*`)
const iHaveContessa = !!~mycards.indexOf(`!`)
const iHaveDuke = !!~mycards.indexOf(`$`)

let state = defaultState

;(async ()=>{
    const data = (await readFile(filename, `utf8`)).replace(/\r/g, ``)

    const isNewGame = data === "" && mycoins === 1 && othercoins === 1

    if (isNewGame) {
        await writeFile(stateFileName, JSON.stringify(state))
    } else {
        state = JSON.parse(await readFile(stateFileName, `utf8`))
    }
    //console.error(state);
    let line = data.split(/\n/g).pop()

    // I am in the exchnage
    if (mycards.length >= 3) {
        const [c1, c2] = GiveCard(true).reverse()

        if (mycards.length === 3) {
            state.inTheDeck.push(c1)
            message(GetRevealCardChar(c1))
        }
        if (mycards.length === 4) {
            state.inTheDeck.push(c1, c2)
            message(`${GetRevealCardChar(c1)}${GetRevealCardChar(c2)}`)
        }
        return await move(`\n`)
    }

    const newTurn = line === ``

    if (newTurn) {
        if (mycoins >= 7) {
            return await move(`C`)
        }

        if (othercoins >= 6) {
            if (iHaveCaptain) 
                return await move(`S`)


            if (mycoins <= 6 && mycards.length <= 1) {
                // TODO: bluff 
            }
        }

        if (
            !iHaveDuke &&
            !iHaveContessa &&
            iHaveAmbassador
        ) {
            return await move(`E`)
        }

        // Assasinate if oponent has no Contessa
        if (
            mycoins >= 3 &&
            iHaveAssassin &&
            !~state.oponentCards.indexOf(CardTypes.Contessa)
        ) {
            return await move(`A`)
        }

        if (iHaveDuke) {

            return await move(`T`)
        }

        return await move(`I\n`)
    }

    // Exchange
    if (line === `Eq`) {
        if (iHaveAmbassador)
            return await move(GetRevealCardChar(CardTypes.Ambassador))

        return await GiveUpCard(GiveCard(true)[0])
    }

    // Tax Challenge
    if(line === `Tq`) {
        if (iHaveDuke)
            return await move(GetRevealCardChar(CardTypes.Duke))

        return await GiveUpCard(GiveCard(true)[0])
    }


    if (line === `Sa`) {
        if (!~state.oponentCards.indexOf(CardTypes.Ambassador)) {
            state.oponentMissingTempCard = CardTypes.Ambassador
            return await move(`q`)
        }
        return await endTurn()
    }

    if (line === `Sc`) {
        if (!~state.oponentCards.indexOf(CardTypes.Captain)) {
            state.oponentMissingTempCard = CardTypes.Captain
            return await move(`q`)
        }
        return await endTurn()
    }

    if (line=== `Saq${GetRevealCardChar(CardTypes.Ambassador)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Ambassador
        );
        return await GiveUpCard(GiveCard(true)[0], true)
    }

    if (line=== `Scq${GetRevealCardChar(CardTypes.Captain)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Captain
        );
        return await GiveUpCard(GiveCard(true)[0], true)
    }

    if (line === `Sq`) {
        if (iHaveCaptain)
            return await move(GetRevealCardChar(CardTypes.Captain))

        return await GiveUpCard(GiveCard(true)[0])
    }

    // Assassinate Block and Chalange it
    if (line === `As`) {
        state.oponentMissingTempCard = CardTypes.Contessa
        return await move(`q`)
    }

    // Assasint blocked by Contessa
    if (line === `Asq${GetRevealCardChar(CardTypes.Contessa)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Contessa
        )
        // Assassin useless here lets give it up
        return await GiveUpCard(CardTypes.Assassin, true)
    }

    // Assassinate challenge
    if (line === `Aq`) {
        if (iHaveAssassin)
            return await move(GetRevealCardChar(CardTypes.Assassin))

        return await GiveUpCard(GiveCard(true)[0])
    }


    // Defense Moves
    if (line === `C`) {
        return await GiveUpCard(GiveCard(true)[0])
    }


    if (line === `A`) {
        if (iHaveContessa)
            return await move(`s`)


        if (!!~state.oponentCards.indexOf(CardTypes.Assassin)) {
            // If oponent has an Assasin card lets bluff
            return await move(`s`)
        } else {
            state.oponentMissingTempCard = CardTypes.Assassin
            return await move(`q`)
        }

    }

    if (line === `Aq${GetRevealCardChar(CardTypes.Assassin)}`) {
        state.oponentMissingTempCard = ``
        state.oponentCards.push(
            CardTypes.Assassin
        );
        return await GiveUpCard(GiveCard(true)[0], true)
    }

    if (line === `Asq`) {
        if (iHaveContessa)
            return await move(GetRevealCardChar(CardTypes.Contessa))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `S`) {
        if (iHaveAmbassador)
            return await move(`a`)

        if (iHaveCaptain)
            return await move(`c`)

        return await move(`p`)
    }

    if (line === `Saq`) {
        if (iHaveAmbassador)
            return await move(GetRevealCardChar(CardTypes.Ambassador))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `Scq`) {
        if (iHaveCaptain)
            return await move(GetRevealCardChar(CardTypes.Captain))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `F`) {
        if (iHaveDuke)
            return await move(`d`)

        return await move(`p`)
    }

    if (line === `Fdq`) {
        if (iHaveDuke)
            return await move(GetRevealCardChar(CardTypes.Duke))

        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `E`) {
        if (!OponentCanHave(CardTypes.Ambassador)) {
            return await move(`q`)
        }

        state.oponentCards = []
        state.oponentMissingCards = []
        state.oponentMissingTempCard = ''

        return await move(`p`)
    }


    if (line === `Eq${GetRevealCardChar(CardTypes.Ambassador)}`) {
        console.error(111, `THIS SHOULD NEVER HAPPEN`)
        return await GiveUpCard(GiveCard(true)[0])
    }

    if (line === `T`) {
        if (!OponentCanHave(CardTypes.Duke)) {
            return await move(`q`)
        }
        return await move(`p`)
    }

    if (line === `Tq${GetRevealCardChar(CardTypes.Duke)}`) {
        console.error(111, `THIS SHOULD NEVER HAPPEN`)
        return await GiveUpCard(GiveCard(true)[0])
    }


    // remove oponents drop card from the state
    // can't detect if oponent has the same card twice
    if (!!~Object.values(giveUpTable).indexOf(line.substr(-1))) {
        // Catch the bluff
        if (state.oponentMissingTempCard !== "") {
            state.oponentMissingCards.push(state.oponentMissingTempCard)
            state.oponentMissingTempCard = ""
        }

        // maybe we should asume user doeas not has the same card?

        const cardType = GetGiveUpCardType(line.substr(-1))
        state.oponentCards.filter(c => c !== cardType)
        state.inTheDeck.push(cardType)
        state.oponentDropedCards.push(cardType)
    }

    return await endTurn()

})()
.then(async () => {
    await writeFile(stateFileName, JSON.stringify(state))
})
.catch(console.error.bind(console))


```

Vì bạn không bao giờ thách thức Trao đổi của đối thủ, bạn có thể muốn tính đến nó, vì nó vô hiệu hóa kiến ​​thức về thẻ của họ.
Tím P

Phiên bản mới đã được cập nhật, Đó là một thỏa thuận với Exchange
Peter

1
Tôi sẽ cập nhật bảng xếp hạng khi bạn xuất bản phiên bản hoàn thiện.
Tím P

Cảm ơn, tôi vừa phát hành Nếu người chơi đưa thẻ của mình ra, thẻ id sẽ bị xóa khỏi tay và thêm lại vào cỗ bài. Điều đó làm cho một nửa logic của tôi sai: DI cần phải sửa nó. (Tôi ngạc nhiên khi tôi đạt được điểm cao như vậy với logic kém) pastebin.com/AXGJ9v5Q <--- 2 lượt cuối! đã bỏ tay tôi ra. Hay là một lỗi?
Peter

Đó không phải là một lỗi. Khi bạn tiết lộ một lá bài để chiến thắng một thử thách, nó sẽ bị xóa khỏi tay bạn và bạn được cấp một lá bài mới từ bộ bài.
Tím P

3

Luật sư

Luật sư thực hiện theo cách thận trọng trên toàn thế giới, không bao giờ nói dối, ngăn chặn khi có thể, thách thức khi không gây bất lợi ngay lập tức. Anh ta không tấn công trừ khi được yêu cầu bằng cách đảo chính, nhưng sẽ lấy tiền thường xuyên nhất có thể để đảo chính nhanh chóng. Anh ta đủ thông minh để hy sinh những thẻ anh ta không sử dụng trước, nhưng không đủ thông minh để sử dụng chúng để loại bỏ chúng và lấy thẻ mới.

import sys

_, filename, othercoins, mycoins, mycards = sys.argv[:5]


def give_card():
    if "^" in mycards:
        return "'"
    if "~" in mycards:
        return "_"
    if "!" in mycards:
        return "="
    if "*" in mycards:
        return "<"
    return "0"


with open(filename, "r+") as history:
    line = "\n"
    for a in history:
        print("line:", a)
        line = a
    if line.endswith("\n"):
        if int(mycoins) >= 10:
            history.write("C")
        elif "$" in mycards:
            history.write("T")
        elif "*" in mycards and int(othercoins) > 0:
            history.write("S")
        else:
            history.write("F")
    elif line == "F":
        if "$" in mycards:
             history.write("d")
        else:
             history.write("p")
    elif line == "C":
        history.write(give_card())
    elif line == "E":
        if len(mycards) > 1:
            history.write("q")
        else: 
            history.write("p")
    elif line == "T":
        if len(mycards) > 1:
            history.write("q")
        else: 
            history.write("p")
    elif line == "A":
        if "!" in mycards:
            history.write("s")
        else: 
            history.write(give_card())
    elif line == "S":
        if "~" in mycards:
            history.write("a")
        elif "*" in mycards:
            history.write("c")
        elif len(mycards) > 1:
            history.write("q")
        else:
            history.write("p")
    elif line.endswith("d") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("a") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("c") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("s") and len(mycards) > 1:
        history.write("q")
    elif line.endswith("sq"):
        history.write("!")
    elif line.endswith("aq"):
        history.write("~")
    elif line.endswith("cq"):
        history.write("*")
    elif line.endswith("dq"):
        history.write("$")
    elif line.endswith("Tq"):
        history.write("$")
    elif line.endswith("Sq"):
        history.write("*")
    elif line[-1] in "~^*!$":
        history.write(give_card())
        if line[-3] in "acds":
            history.write("\n")
    else:
        history.write("\n")

Có lẽ có lỗi trong chương trình này. Khi bạn tìm thấy chúng, xin vui lòng cho tôi biết.


@PurpleP Điểm tốt. Tôi đã sửa nó. Kỹ năng ra quyết định là rất quan trọng đối với một luật sư giỏi.
Hiatsu

Bạn đã xác minh rằng tập tin trên thực tế không kết thúc bằng một dòng mới? (ví dụ: mở tệp và nhìn thấy một chữ in hoa ở giữa dòng?) Tôi đang xem xét nguyên nhân của việc này và muốn đảm bảo rằng nó được loại trừ.
Hiatsu

@PurpleP Tôi có thể tải lên phiên bản gỡ lỗi sử dụng STDOUT cho các mục đích không trao đổi và bạn có gửi lại kết quả cho tôi không?
Hiatsu


Mặt nạ và Luật sư có thể đi vào một vòng lặp khiến cả hai mất. Nếu Lawyer có một thẻ không phải là Công tước, nó sẽ luôn cố gắng đánh cắp. Sau đó, Mask sẽ luôn yêu cầu một Đại sứ chặn nó và Trao đổi để che dấu vết của nó. Ví dụ trò chơi. Tôi không phàn nàn hoặc yêu cầu bạn sửa nó; Tôi chỉ muốn bạn biết vì nó thật hài hước.
Tím P

2

Ngẫu nhiên

Ngẫu nhiên không biết phải làm gì, vì vậy anh ta chọn ngẫu nhiên một cái gì đó hợp pháp.

package main

import (
    "fmt"
    "math/rand"
    "os"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())
    filename := os.Args[1]
    ourCards := os.Args[4]
    legalActions := os.Args[5:]
    file, _ := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND, 0755)
    defer file.Close()

    file.WriteString(legalActions[rand.Intn(len(legalActions))])
    switch len(ourCards) {
    case 3:
        os.Stdout.Write([]byte{ourCards[rand.Intn(3)]})
    case 4:
        i1 := 0
        i2 := 0
        for ok := true; ok; ok = i1 == i2 {
            i1 = rand.Intn(4)
            i2 = rand.Intn(4)
        }
        keptCards := []byte{ourCards[i1], ourCards[i2]}
        os.Stdout.Write(keptCards)
    }
}

Người thách thức

Challenger tin tưởng không ai trong trò chơi lừa dối này. Nếu bạn làm điều gì đó thách thức, anh ấy sẽ thách thức bạn. Nếu không, anh ta chỉ nhận thu nhập mỗi lượt và cố gắng đảo chính bạn nếu anh ta có tiền.

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "os"
    "strconv"
)

var revealToPunishment = map[byte]byte{'~': '_', '^': '\'', '*': '<', '!': '=', '$': '0'}

func main() {
    filename := os.Args[1]
    coinCount := os.Args[3]
    ourCards := os.Args[4]
    file, _ := os.OpenFile(filename, os.O_RDWR, 0755)
    defer file.Close()

    rawBytes, _ := ioutil.ReadAll(file)
    if len(rawBytes) == 0 {
        file.Write([]byte("I\n"))
        return
    }
    lines := bytes.Split(rawBytes, []byte{'\n'})
    switch rawBytes[len(rawBytes)-1] {
    case '\n':
        // Our turn, do we have enough coins for a Coup?
        if c, _ := strconv.Atoi(coinCount); c >= 7 {
            file.Write([]byte{'C'})
            // We don't, so take income.
        } else {
            file.Write([]byte("I\n"))
        }
    // Opponent did something challengeable. We don't believe them for a second.
    // Challenge it.
    case 'E', 'T', 'A', 'S', 'a', 'c', 'd', 's':
        file.Write([]byte{'q'})
    // Opponent Couped us or our challenge failed. Give up a card.
    case 'C':
        file.Write([]byte{revealToPunishment[ourCards[0]]})
    case '~', '*', '^', '!', '$':
        file.Write([]byte{revealToPunishment[ourCards[0]]})
        lastLine := lines[len(lines)-1]
        switch lastLine[len(lastLine)-3] {
        case 'a', 'c', 'd', 's':
            file.WriteString("\n")
        }
    // Our challenge succeeded or we Couped the opponent! End our turn.
    case '_', '\'', '<', '=', '0':
        file.Write([]byte{'\n'})
    default:
        // Opponent took some other action. Let it pass.
        file.Write([]byte{'p'})
    }
}

Biên dịch các chương trình này với go build random.go/challenger.govà chạy với ./randomhoặc ./challenger.


Tôi khuyên bạn không nên chỉ định giới tính cho các chương trình máy tính. Đã có đủ sự thiên vị về giới tính trong các cộng đồng lập trình và các đại từ mặc định của nam giới chứng minh thêm rằng phụ nữ không được chào đón.
Greg Martin

2

Nhân viên thuế

Taxman ở đây để thu thuế. Sử dụng sát thủ nếu họ có. Chỉ chặn nếu họ có thẻ để chặn. Thử thách ngẫu nhiên.

Được viết bằng c #, tôi đã dành quá nhiều thời gian để xây dựng một hệ thống phân cấp lớp cho tất cả các hành động khác nhau có thể được thực hiện.

Chỉnh sửa: Bây giờ với logic được cải thiện như không tuyên bố có công tước khi họ đã từ bỏ công tước sau khi bị thách thức. Cũng không còn cố gắng liên tục ám sát nếu đối thủ chặn bằng contessa (và không bị thách thức).

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

internal static class Program
{
    public static void Main(string[] args)
    {
#if DEBUG
        // Can't figure out how to pass newline as a command line arg.
        for (int i = 0; i < args.Length; i++)
        {
            if (args[i] == "I\\n")
                args[i] = "I\n";
        }
#endif
        if (!ProcessArgs(args, out string filename, out int opCoin, out int myCoin, out IEnumerable<Card> cards, out IEnumerable<Output> validOutputs))
        {
            Console.WriteLine("Error with args.");
            return;
        }

        var taxman = new Taxman(filename, opCoin, myCoin, cards, validOutputs);
        taxman.DukeEm();
    }

    private static bool ProcessArgs(string[] args, out string filename, out int opCoin, out int myCoin, out IEnumerable<Card> cards, out IEnumerable<Output> validOutputs)
    {
        if (args.Length < 4)
        {
            throw new InvalidOperationException("Error: Not enough args.");
        }
        bool success = true;

        filename = args[0];
        success &= int.TryParse(args[1], out opCoin) && opCoin >= 0 && opCoin <= 12;
        success &= int.TryParse(args[2], out myCoin) && myCoin >= 0 && myCoin <= 12;

        cards = Card.ParseSymbols(args[3]);

        IEnumerable<char> validOutputArgs = args.Skip(4).Select(outputArg => outputArg.First());
        // Income and Surrenders on our turn include \n, we use chars below so don't include the newline, hence the call to .First().
        // Code below should be smart enough to also write a newline if necessary.

        validOutputs = Output.ParseSymbols(validOutputArgs);
        return success;
    }
}

internal sealed class Taxman
{
    private const string _OustedAsDukeFileName = "MyTotallyCoolStateFile.txt";
    private const string _OppClaimsContessaFileName = "OppClaimsContess.txt";
    private readonly Random _Rand = new Random();
    private readonly List<Card> _GiveUpPreferences = new List<Card> { Card.Duke, Card.Assassin, Card.Ambassador, Card.Contessa, Card.Captain };

    private double BaseProbabilityToChallenge => 0.1d;
    private bool _Written = false;
    private bool _MyTurn;
    private bool? _OustedAsDuke = null;
    private bool? _OppClaimsContessa = null;

    private string FileName { get; }
    private int OppCoin { get; }
    private int MyCoin { get; }
    private IEnumerable<Card> Cards { get; }
    private IEnumerable<Output> ValidOutputs { get; }
    private IEnumerable<Output> GameSoFar { get; }
    private int OppCardCount { get; }
    private int MyCardCount => Cards.Count();

    private int OppScore => (10 * OppCardCount) + OppCoin;
    private int MyScore => (10 * MyCardCount) + MyCoin;

    private bool OustedAsDuke
    {
        get
        {
            if (_OustedAsDuke.HasValue)
            {
                return _OustedAsDuke.Value;
            }
            else
            {
                if (string.IsNullOrWhiteSpace(File.ReadAllText(_OustedAsDukeFileName)))
                {
                    _OustedAsDuke = false;
                    return false;
                }
                else
                {
                    _OustedAsDuke = true;
                    return true;
                }
            }
        }
        set
        {
            File.WriteAllText(_OustedAsDukeFileName, value ? "Ousted" : string.Empty);
            _OustedAsDuke = value;
        }
    }

    private bool OppClaimsContessa
    {
        get
        {
            if (_OppClaimsContessa.HasValue)
            {
                return _OppClaimsContessa.Value;
            }
            else
            {
                if (string.IsNullOrWhiteSpace(File.ReadAllText(_OppClaimsContessaFileName)))
                {
                    _OppClaimsContessa = false;
                    return false;
                }
                else
                {
                    _OppClaimsContessa = true;
                    return true;
                }
            }
        }
        set
        {
            File.WriteAllText(_OppClaimsContessaFileName, value ? "Claimed" : string.Empty);
            _OppClaimsContessa = value;
        }
    }

    public Taxman(string fileName, int oppCoin, int myCoin, IEnumerable<Card> cards, IEnumerable<Output> validOutputs)
    {
        FileName = fileName; OppCoin = oppCoin; MyCoin = myCoin; Cards = cards; ValidOutputs = validOutputs;

        GameSoFar = ReadFile();

        //calculate how many cards the opponent has.
        int giveUps = GameSoFar.Count(output => output is GiveUp);
        int myGiveUps = 2 - MyCardCount;
        var oppGiveUps = giveUps - myGiveUps;
        OppCardCount = 2 - oppGiveUps;
    }

    public void DukeEm()
    {
        if (Cards.Skip(2).Any())
        {
            Exchange();
            Write(Output.EndTurn);
            return;
        }

        var prev = GameSoFar.LastOrDefault() ?? Output.EndTurn;
        if (prev == Output.EndTurn) // Income is I\n so shows up as an EndTurn
        {
            ChooseAction();
        }
        else if (prev == Action.ForeignAid)
        {
            if (!OustedAsDuke)
                Write(Block.Duke);
            else
                Write(Output.Pass);
        }
        else if (prev == Action.Coup)
        {
            GiveUpDecide();
        }
        else if (prev == ChallengeableAction.Exchange || prev == ChallengeableAction.Tax)
        {
            if (ShouldChallenge((ChallengeableAction)prev))
                Write(Output.Challenge);
            else
                Write(Output.Pass);
        }
        else if (prev == ChallengeableAction.Assassinate)
        {
            RespondToAssassinate();
        }
        else if (prev == ChallengeableAction.Steal)
        {
            RespondToSteal();
        }
        else if (prev == Block.Duke || prev == Block.Ambassador || prev == Block.Captain || prev == Block.Contessa)
        {
            Debug.Assert(prev == Block.Contessa, "We should never take an action that a different card would block.");

            if (ShouldChallenge((Block)prev))
                Write(Output.Challenge);
            else
            {
                Write(Output.EndTurn);
                OppClaimsContessa = true;
            }
        }
        else if (prev == Output.Pass)
        {
            Write(Output.EndTurn);
        }
        else if (prev == Output.Challenge)
        {
            var challengedOutput = (IChallengeable)GameSoFar.TakeLast(2).First();
            RespondToChallenge(challengedOutput);
        }
        else if (prev is Card)
        {
            GiveUpDecide();
        }
        else if (prev is GiveUp)
        {
            if (prev == GiveUp.Contessa)
                OppClaimsContessa = false;

            Write(Output.EndTurn);
        }
        else
        {
            Debug.Fail("Should have hit one of the conditions above.");
            WriteRandomValid();
        }
    }

    private void Exchange()
    {
        int handSize = MyCardCount - 2;
        var cardsToKeep = new List<Card>();
        var workingCards = Cards.ToList();

        while (cardsToKeep.Count < handSize)
        {
            if (!cardsToKeep.Contains(Card.Duke) && workingCards.Remove(Card.Duke))
                cardsToKeep.Add(Card.Duke);
            else if (!cardsToKeep.Contains(Card.Assassin) && !OppClaimsContessa && workingCards.Remove(Card.Assassin))
                cardsToKeep.Add(Card.Assassin);
            else if (!cardsToKeep.Contains(Card.Ambassador) && workingCards.Remove(Card.Ambassador))
                cardsToKeep.Add(Card.Ambassador);
            else if (!cardsToKeep.Contains(Card.Contessa) && workingCards.Remove(Card.Contessa))
                cardsToKeep.Add(Card.Contessa);
            else if (!cardsToKeep.Contains(Card.Captain) && workingCards.Remove(Card.Captain))
                cardsToKeep.Add(Card.Captain);
            else
            {
                cardsToKeep.Add(workingCards[0]);
                workingCards.RemoveAt(0);
            }
        }
        var keptCards = new string(cardsToKeep.Select(card => card.Symbol).ToArray());
        Console.WriteLine(keptCards);
    }

    private IEnumerable<Output> ReadFile()
    {
        var text = File.ReadAllText(FileName);

        // Check if we're at the start of the game, 1 character means our opponent went first.
        if (text == null || text.Length <= 1)
        {
            // Do any start up like creating a state file.
            Debug.Assert(MyCardCount == 2 && MyCoin == 1 && OppCoin == 1, "Should always start with 2 cards in hand and have 1 coin each.");
            using (File.Create(_OustedAsDukeFileName))
            using (File.Create(_OppClaimsContessaFileName))
            { ; }
        }

        var lastLine = text.Split('\n').LastOrDefault();
        _MyTurn = lastLine == null || lastLine.Length % 2 == 0;

        return Output.ParseSymbols(text);
    }

    private void ChooseAction()
    {
        if (MyCoin >= 3 && Cards.Contains(Card.Assassin))
        {
            // If we have the coins to assasinate and have the card to assasinate then go for it.
            Write(ChallengeableAction.Assassinate);
        }
        else if (MyCoin >= 7)
        {
            // If we have the coins to coup then go for it.
            Write(Action.Coup);
        }
        else if (Cards.Contains(Card.Ambassador) && !Cards.Contains(Card.Duke))
        {
            // If we don't /actually/ have a duke but we do have ambassador and can exchange into one, then try do that.
            Write(ChallengeableAction.Exchange);
            // TODO if we've exchanged multiple times already perhaps we should try something different?
        }
        else if (!OustedAsDuke)
        {
            // Take tax because We totally always have a duke.
            // Except if we've been previously challenged and shown to not have a duke, in which case exchange to get a new Duke.
            Write(ChallengeableAction.Tax);
        }
        else
        {
            Write(ChallengeableAction.Exchange);
            // Even if we don't find a duke from the exchange we can pretend that we did.
            OustedAsDuke = false;
        }
    }

    private void RespondToAssassinate()
    {
        if (Cards.Contains(Card.Contessa))
            Write(Block.Contessa);
        else if (MyCardCount <= 1)
        {
            // We will lose if we don't challenge or block.
            if (ShouldRandomChallenge(0.5d))
                Write(Output.Challenge);
            else
                Write(Block.Contessa);
        }
        else if (ShouldChallenge(ChallengeableAction.Assassinate))
            Write(Output.Challenge);
        else
            GiveUpDecide();
    }

    private void RespondToSteal()
    {
        // prefer to block with ambassador before captain.
        if (Cards.Contains(Card.Ambassador))
            Write(Block.Ambassador);
        else if (Cards.Contains(Card.Captain))
            Write(Block.Captain);
        else if (ShouldChallenge(ChallengeableAction.Steal))
            Write(Output.Challenge);
        else
            Write(Output.Pass);
        // TODO if opp is continually stealing we need to figure out who wins the race if we keep taking Tax.
    }

    private void RespondToChallenge(IChallengeable challengedAction)
    {
        if (Cards.Contains(challengedAction.RequiredCard))
            Write(challengedAction.RequiredCard);
        else
            GiveUpDecide();

        if (challengedAction == ChallengeableAction.Tax)
            OustedAsDuke = true;
    }

    private void GiveUpDecide()
    {
        Write(Cards.OrderBy(card => _GiveUpPreferences.IndexOf(card)).Last().GiveUp);

        if (_MyTurn)
            Write(Output.EndTurn);
    }

    private bool ShouldChallenge(IChallengeable prev)
    {
        // Never challenge if we're far enough ahead, always challenge if far enough behind
        if (MyScore > (OppScore + 7))
        {
            return false;
        }
        else if (MyScore < (OppScore - 10))
        {
            return true;
        }
        else
        {
            if (prev == ChallengeableAction.Assassinate)
                return ShouldRandomChallenge(BaseProbabilityToChallenge * 0.5d);
            else if (prev is Block)
                return ShouldRandomChallenge(BaseProbabilityToChallenge * 2d);
            else if (prev == ChallengeableAction.Tax && OppCoin >= 4 && MyCardCount <= 1 && (MyCoin < 7 || OppCardCount > 1))
                return true;
            else
                return ShouldRandomChallenge(BaseProbabilityToChallenge);
        }
    }

    private bool ShouldRandomChallenge(double prob)
    {
        return _Rand.NextDouble() < prob;
    }

    private void WriteRandomValid()
    {
        int index = _Rand.Next(0, ValidOutputs.Count());
        var randomOutput = ValidOutputs.ElementAt(index);
        Write(randomOutput);
    }

    private void Write(Output output)
    {
        Debug.Assert(!_Written || (_MyTurn && output == Output.EndTurn), "If we've already written a value we shouldn't be trying to write another.");
        Debug.Assert(ValidOutputs.Contains(output), "Should only be writing valid outputs to file.");

        File.AppendAllText(FileName, output.Symbol.ToString());
        _Written = true;
    }
}

[DebuggerDisplay("{Symbol}")]
internal class Output
{
    public static readonly Output Pass = new Output() { Symbol = 'p' };
    public static readonly Output Challenge = new Output() { Symbol = 'q' };
    public static readonly Output EndTurn = new Output() { Symbol = '\n' };

    private static readonly Output[] _BaseOutputs = new Output[3] { Pass, Challenge, EndTurn };

    protected Output() { }

    public static IEnumerable<Output> AllOutputs => ChallengeableAction.Actions.Concat(Block.Blocks.Concat(Card.Cards.Concat(GiveUp.GiveUps.Concat(_BaseOutputs))));

    public static IList<Output> ParseSymbols(IEnumerable<char> symbols)
    {
        var parsedOutputs = new List<Output>();
        foreach (var symbol in symbols)
        {
            if (symbol == '\r') continue; // newlines can show up as \r\n so need to skip the \r.
            var matchingOutput = AllOutputs.FirstOrDefault(output => output.Symbol == symbol);
            if (matchingOutput == null)
            {
                throw new InvalidOperationException($"Could not parse Output symbol: \"{symbol}\"");
            }
            parsedOutputs.Add(matchingOutput);
        }
        return parsedOutputs;
    }

    public char Symbol { get; protected set; }
}

internal sealed class Card : Output
{
    public static readonly Card Ambassador = new Card() { Symbol = '~', GiveUp = GiveUp.Ambassador, AvailableAction = ChallengeableAction.Exchange, AvalableBlock = Block.Ambassador };
    public static readonly Card Assassin = new Card() { Symbol = '^', GiveUp = GiveUp.Assassin, AvailableAction = ChallengeableAction.Assassinate };
    public static readonly Card Captain = new Card() { Symbol = '*', GiveUp = GiveUp.Captain, AvailableAction = ChallengeableAction.Steal, AvalableBlock = Block.Captain };
    public static readonly Card Contessa = new Card() { Symbol = '!', GiveUp = GiveUp.Contessa, AvalableBlock = Block.Contessa };
    public static readonly Card Duke = new Card() { Symbol = '$', GiveUp = GiveUp.Duke, AvailableAction = ChallengeableAction.Tax, AvalableBlock = Block.Duke };

    private static readonly Card[] _Cards = new Card[5] { Ambassador, Assassin, Captain, Contessa, Duke };

    private Card() { }

    public static IEnumerable<Card> Cards => _Cards;

    public GiveUp GiveUp { get; private set; }
    public ChallengeableAction AvailableAction { get; private set; }//=> ChallengeableAction.ChallengeableActions.SingleOrDefault(action => action.RequiredCard == this);
    public Block AvalableBlock { get; private set; }// => Block.Blocks.SingleOrDefault(block => block.RequiredCard == this);

    new public static IEnumerable<Card> ParseSymbols(IEnumerable<char> cardSymbols)
    {
        var parsedCards = new List<Card>();
        foreach (var symbol in cardSymbols)
        {
            var matchingCard = Cards.FirstOrDefault(card => card.Symbol == symbol);
            if (matchingCard == null) throw new InvalidOperationException($"Could not parse card symbol: {symbol}");
            parsedCards.Add(matchingCard);
        }
        return parsedCards;
    }
}

internal class Action : Output
{
    public static readonly Action Income = new Action() { Symbol = 'I' };
    public static readonly Action ForeignAid = new Action() { Symbol = 'F', BlockedBy = new Block[1] { Block.Duke } };
    public static readonly Action Coup = new Action() { Symbol = 'C' };

    protected Action() : base() { }

    public IEnumerable<Block> BlockedBy { get; protected set; } = new Block[0];
}

internal sealed class ChallengeableAction : Action, IChallengeable
{
    public static readonly ChallengeableAction Tax = new ChallengeableAction() { Symbol = 'T' };
    public static readonly ChallengeableAction Assassinate = new ChallengeableAction() { Symbol = 'A', BlockedBy = new Block[1] { Block.Contessa } };
    public static readonly ChallengeableAction Exchange = new ChallengeableAction() { Symbol = 'E' };
    public static readonly ChallengeableAction Steal = new ChallengeableAction { Symbol = 'S', BlockedBy = new Block[2] { Block.Ambassador, Block.Captain } };

    private static readonly Action[] _Actions = new Action[7] { Income, ForeignAid, Coup, Tax, Assassinate, Exchange, Steal };
    private static readonly ChallengeableAction[] _ChallengeableActions = new ChallengeableAction[4] { Tax, Assassinate, Exchange, Steal };

    private ChallengeableAction() : base() { }

    public static IEnumerable<Action> Actions => _Actions;
    public static IEnumerable<ChallengeableAction> ChallengeableActions => _ChallengeableActions;

    public Card RequiredCard => Card.Cards.Single(card => card.AvailableAction == this);
}

internal sealed class Block : Output, IChallengeable
{
    public static readonly Block Duke = new Block() { Symbol = 'd' };
    public static readonly Block Ambassador = new Block() { Symbol = 'a' };
    public static readonly Block Captain = new Block() { Symbol = 'c' };
    public static readonly Block Contessa = new Block() { Symbol = 's' };

    private static readonly Block[] _Blocks = new Block[4] { Ambassador, Captain, Contessa, Duke };

    private Block() : base() { }

    public static IEnumerable<Block> Blocks => _Blocks;

    public Card RequiredCard => Card.Cards.Single(card => card.AvalableBlock == this);
    public Action ActionBlocked => ChallengeableAction.Actions.Single(action => action.BlockedBy.Contains(this));
}

internal sealed class GiveUp : Output
{
    public static readonly GiveUp Ambassador = new GiveUp() { Symbol = '_' };
    public static readonly GiveUp Assassin = new GiveUp() { Symbol = '\'' };
    public static readonly GiveUp Captain = new GiveUp() { Symbol = '<' };
    public static readonly GiveUp Contessa = new GiveUp() { Symbol = '=' };
    public static readonly GiveUp Duke = new GiveUp() { Symbol = '0' };

    private static readonly GiveUp[] _GiveUps = new GiveUp[5] { Ambassador, Assassin, Captain, Contessa, Duke };

    private GiveUp() : base() { }

    public static IEnumerable<GiveUp> GiveUps => _GiveUps;

    public Card Card => Card.Cards.Single(card => card.GiveUp == this);
}

internal interface IChallengeable { Card RequiredCard { get; } }

Tôi không thể nhận xét về bài đăng gốc, nhưng tôi muốn chỉ ra một lỗi trong trọng tài, trong đó determine_turn_effects(), hành động Đánh cắp là lấy hết tiền của đối thủ. Nó nên được lấy nhiều nhất là hai đồng tiền.
Dysnomian

Khi chương trình này cố gắng trao đổi, nó bị mất bằng cách xuất ra một chuỗi trống. Trò chơi ví dụ so với Ngẫu nhiên.
Tím P

Tôi đã biên dịch nó với studio hình ảnh trên cửa sổ. Khi tôi về nhà, tôi chắc chắn rằng nó cũng hoạt động với Mono. Trao đổi đang sử dụng Console.WriteLine () để ghi vào std out. Điều này hoạt động khi tôi thử nghiệm nó, tôi sẽ điều tra thêm và cập nhật nó.
Dysnomian

1
Tôi nghĩ vấn đề là bạn đang kiểm tra "lastArg", nhưng thẻ Exchange được trao cho bạn ở chỉ số 3 như các thẻ khác của bạn.
Tím P

1
Đã thêm vào bảng thành tích.
Tím P

1

Luật sư Rando Aggro

Tương tự như luật sư, nó chỉ làm những điều hợp pháp. Tuy nhiên, nó ám sát, đảo chính trước đó và nó chọn một số hành động ngẫu nhiên (như khi nào Thử thách).

#! /usr/bin/env python3
import sys
import random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]


def give_card():
    if "~" in mycards: # give up Ambassador
        return "_"
    if "!" in mycards: # give up Contessa
        return "="
    if "^" in mycards: # give up Assassin
        return "'"
    if "*" in mycards: # give up Captain
        return "<"
    return "0" # give up Duke


with open(filename, "r+") as history:
    line = "\n"
    for a in history:
        line = a # get the last line of the file
    print("{}, {}, {}, {}".format(line, othercoins, mycoins, mycards))
    if line.endswith("\n"): # it has an endline, eg this is a new action
        if int(mycoins) >= 7:
            history.write("C") # coup if I have to
        elif int(mycoins) >= 3 and "^" in mycards:
            history.write("A") # assassinate if I can
        elif "*" in mycards and int(othercoins) > 0:
            history.write("S") # steal if i can
        elif "$" in mycards:
            history.write("T") # tax if i can
        elif random.randint(0,1):
            history.write("F") # foreign aid 50% of the time
        else:
            history.write("I\n") # income
    elif line == "F": # they tried to foreign aid
        if "$" in mycards:
             history.write("d") # block if i can
        else:
             history.write("p")
    elif line == "C": # they coup, sad
        history.write(give_card())
    elif line == "E": # they Exchange
        if random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else: 
            history.write("p") 
    elif line == "T": # they tax
        if random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else: 
            history.write("p") 
    elif line == "A": # they assassinate
        if "!" in mycards:
            history.write("s") # block with contessa if i can
        elif random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else: 
            history.write(give_card()) # otherwise give up a card
    elif line == "S": # they steal
        if "~" in mycards:
            history.write("a") # block with ambassador if i can
        elif "*" in mycards:
            history.write("c") # block with captain if i can
        elif random.randint(0,1):
            history.write("q") # challenge 50% of the time
        else:
            history.write("p")
    elif line.endswith("d") and random.randint(0,1): # they block my foreign aid
        history.write("q") # challenge 50% of the time
    elif line.endswith("a") and random.randint(0,1): # they block as ambassador
        history.write("q") # challenge 50% of the time
    elif line.endswith("c") and random.randint(0,1): # they block as captain
        history.write("q") # challenge 50% of the time
    elif line.endswith("s") and random.randint(0,1): # they block as contessa
        history.write("q") # challenge 50% of the time
    elif line.endswith("sq"): # they challenged my contessa block
        history.write("!") # reveal that i have contessa (no condition because i never lie block)
    elif line.endswith("aq"): # they challenge my Ambassador block
        history.write("~") # reveal that i have a captain (no condition because i never lie block)
    elif line.endswith("cq"): # they challenged my Captain block
        history.write("*") # reveal that I have a Captain (no condition because i never lie block)
    elif line.endswith("dq"): # they challenge my Duke block
        history.write("$") # reveal that I have a Duke (no condition because i never lie block)
    elif line.endswith("Tq"): # they challenge my Tax 
        history.write("$") # reveal that I have a Duke (no condition because i fake tax)
    elif line.endswith("Aq"): # they challenge my assassinate
        history.write("^") # reveal that I had an Assasin
    elif line.endswith("Sq"): # they challenge my steal
        history.write("*") # reveal that I have a Captain
    elif line[-1] in "~^*!$": # they respond to my challenge successfully
        history.write(give_card()) # give up card
        if line[-3] in "acds":
            history.write("\n")
    else:
        history.write("\n")
    history.seek(0)
    print("out")
    print(history.read())

Tôi đã sắp xếp chức năng give_card để từ bỏ thẻ mà Luật sư không sử dụng trước tiên. Nếu bạn thực sự sử dụng Assassin, bạn có thể muốn sắp xếp lại chức năng đó để giữ nó lâu hơn.
Hiatsu

Cảm ơn vì đã nhận thấy điều đó, tôi đã chọn lệnh đó với hy vọng sẽ khiến nó sử dụng đại sứ nhưng hết thời gian. Tôi đã thay đổi thứ tự từ bỏ để có ý nghĩa hơn và cũng làm cho nó nhanh hơn bằng cách ăn cắp trước khi đánh thuế.
gggg

1

Mặt nạ

Mặt nạ là một bậc thầy cải trang. Anh ta ngăn chặn đối thủ theo dõi các thẻ của mình bằng cách trao đổi mỗi khi anh ta hành động hoặc chặn. Chiến lược chiến thắng của anh ta là lấy 3 đồng xu làm Công tước, sau đó là Sát thủ.

Biên dịch với go build mask.go, chạy với ./mask.

package main

import (
    "bytes"
    "io/ioutil"
    "os"
    "strconv"
    "strings"
)

var revealToPunishment = map[byte]byte{'~': '_', '^': '\'', '*': '<', '!': '=', '$': '0'}
var assertedCardMap = map[byte]byte{'A': '^', 'E': '~', 'S': '*', 'T': '$', 'a': '~', 'c': '*', 's': '!', 'd': '$'}

func actWithOneCard(file *os.File, coinCount int, ourCards string) {
    if coinCount >= 7 {
        file.WriteString("C")
    } else if ourCards == "$" {
        file.WriteString("T")
    } else {
        file.WriteString("I\n")
    }
}

func mostRecentClaim(lines [][]byte) byte {
    // If we blocked and were not challenged on the opponent's last turn, return
    // what we claimed to have in the block.
    opponentsLastTurn := lines[len(lines)-1]
    switch b := opponentsLastTurn[len(opponentsLastTurn)-1]; b {
    case 'a', 'c', 's', 'd':
        return b
    }
    // Otherwise, return the first character of our last turn.
    ourLastTurn := lines[len(lines)-2]
    return ourLastTurn[0]
}

func whatWePlanToDoNext(lines [][]byte, coinCount int) string {
    if len(lines) < 2 || mostRecentClaim(lines) == 'E' {
        if coinCount >= 3 {
            return "A"
        } else {
            return "T"
        }
    } else {
        return "E"
    }
}

func ourTurn(file *os.File, coinCount int, ourCards string, lines [][]byte) {
    if len(ourCards) == 1 {
        actWithOneCard(file, coinCount, ourCards)
        return
    }
    file.WriteString(whatWePlanToDoNext(lines, coinCount))
}

func handleChallenge(file *os.File, ourCards string, lines [][]byte) {
    lastLine := lines[len(lines)-1]
    attemptedAction := lastLine[len(lastLine)-2]
    assertedCard := assertedCardMap[attemptedAction]
    for i := range ourCards {
        if ourCards[i] == assertedCard && ourCards[i] != '\x00' {
            file.Write([]byte{assertedCard})
            return
        }
    }
    cardToGiveUp := giveUpCard(ourCards)
    file.Write([]byte{revealToPunishment[cardToGiveUp]})
    switch attemptedAction {
    case 'a', 'c', 'd', 's':
    default:
        file.WriteString("\n")
    }
}

func giveUpCard(ourCards string) byte {
    // If we have a Duke, give up the other card.
    if dukeIndex := strings.Index(ourCards, "$"); -1 < dukeIndex && len(ourCards) == 2 {
        return ourCards[(dukeIndex+1)%2]
    }
    return ourCards[0]
}

func main() {
    filename := os.Args[1]
    coinCount, _ := strconv.Atoi(os.Args[3])
    ourCards := os.Args[4]
    file, _ := os.OpenFile(filename, os.O_RDWR, 0755)
    defer file.Close()

    rawBytes, _ := ioutil.ReadAll(file)
    lines := bytes.Split(rawBytes, []byte{'\n'})
    if len(lines[len(lines)-1]) == 0 {
        lines = lines[:len(lines)-1]
    }
    if len(rawBytes) == 0 {
        file.WriteString("T")
        return
    }
    // Exchange. Prioritize Ambassador, Duke, Assassin.
    if len(ourCards) > 2 {
        var has_ambassador, has_duke, has_assassin bool
        var keptCards string
        for len(ourCards) > 2 {
            var i int
            if i = strings.Index(ourCards, "~"); !has_ambassador && i > -1 {
                keptCards += "~"
                has_ambassador = true
                ourCards = ourCards[:i] + ourCards[i+1:]
            } else if i = strings.Index(ourCards, "$"); !has_duke && i > -1 {
                keptCards += "$"
                has_duke = true
                ourCards = ourCards[:i] + ourCards[i+1:]
            } else if i = strings.Index(ourCards, "^"); !has_assassin && i > -1 {
                keptCards += "^"
                has_assassin = true
                ourCards = ourCards[:i] + ourCards[i+1:]
            } else {
                keptCards += ourCards[:1]
                ourCards = ourCards[1:]
            }
        }
        ourCards = keptCards
        os.Stdout.WriteString(ourCards)
    }
    switch rawBytes[len(rawBytes)-1] {
    case '\n':
        ourTurn(file, coinCount, ourCards, lines)
    // Opponent Couped us. Give up a card.
    case 'C':
        file.Write([]byte{revealToPunishment[giveUpCard(ourCards)]})
    // Opponent blocked, or we Assassinated/Couped them. End our turn.
    case 'a', 'c', 'd', 's', 'p', '_', '\'', '<', '=', '0':
        file.WriteString("\n")
    case 'q':
        handleChallenge(file, ourCards, lines)
    // Opponent did something blockable, block it.
    case 'F':
        file.WriteString("d")
    case 'A':
        file.WriteString("s")
    case 'S':
        if strings.Contains(ourCards, "*") {
            file.WriteString("c")
        } else {
            file.WriteString("a")
        }
    // Opponent took some other action. Let it pass.
    default:
        file.WriteString("p")
    }
}

Tôi khuyên bạn không nên chỉ định giới tính cho các chương trình máy tính. Đã có đủ sự thiên vị về giới tính trong các cộng đồng lập trình và các đại từ mặc định của nam giới chứng minh thêm rằng phụ nữ không được chào đón.
Greg Martin

3
@GregMartin Nếu bất kỳ người phụ nữ nào nói rằng việc tôi đưa ra những lời đệ trình kỳ quặc của tôi, tưởng tượng họ là những cận thần như trong trò chơi bài, khiến cô ấy cảm thấy bị xúc phạm hoặc không được chào đón, thì tôi sẽ thay đổi nó trong tích tắc. Nhưng bạn không phải là phụ nữ, Greg. Và tôi không thích rằng bạn đã gửi đến những tiêu cực câu trả lời mà tôi đã nỗ lực nhiều nhất, và câu trả lời tốt nhất trong thử thách của riêng tôi - không phải vì nó không liên quan hay là một câu trả lời tồi cho câu hỏi, mà là vì một kẻ giả mạo xã hội nhỏ .
Tím P

1

Con bạc

Con bạc có một chiến lược xác thực nhưng tin tưởng vào ruột của mình khi một tình huống không được tính đến trong chiến lược chiến thắng của anh ta. Anh ta cố gắng ăn cắp rất nhiều và đảo chính / ám sát bất cứ khi nào có thể.

Viết bằng Python3:

import sys
import random
import time

random.seed(time.time())  # lets keep it rather random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legal_actions = sys.argv[5:]

othercoins = int(othercoins)
mycoins = int(mycoins)

income = 'I\n'

foreign_aid, coup, exchange, tax, assassinate, steal, block_aid, \
block_steal_amb, block_steal_cap, block_assassinate, \
pass_challange, do_challenge = "FCETASdacspq"


loosing_actions = "_'<=0"
loose_ambassador, loose_assassin, loose_captain, loose_contessa, loose_duke = loosing_actions
have_ambassador, have_assassin, have_captain, \
have_contessa, have_duke = "~^*!$"

actions_dict = {
    exchange: loose_ambassador, tax: loose_duke, assassinate: loose_assassin, steal: loose_captain,
    block_aid: loose_duke, block_steal_amb: loose_ambassador, block_steal_cap: loose_captain, block_assassinate: loose_contessa
}


def guess_opponents_hand():
    # get number of each card still in play and not in hand
    card_counts = [3] * 5
    card_give_up = list("_'<=0")
    with open(filename, 'r') as history:
        while True:
            line = history.readline()
            if not line:
                break
            for card in card_give_up:
                if card in line:
                    card_counts[card_give_up.index(card)] -= 1

    have_cards = list("~^*!$")

    if sum(card_counts) == 15:
        num_cards = 2
    elif sum(card_counts) == 14:
        if len(mycards) == 1:
            num_cards = 2
        else:
            num_cards = 1
    else:
        num_cards = 1

    for card in mycards:
        card_counts[have_cards.index(card)] -= 1

    # randomly sample a hand for the opponent
    card_1 = sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)
    if num_cards == 1:
        return card_1
    card_counts[card_give_up.index(card_1)] -= 1
    return card_1 + sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)


def sample_from_probabilities(success_probabilities, actions):
    # weighted random
    return random.choices(actions, success_probabilities)[0]

def get_prev_char(line, x=1):
    try:
        return line[-1*x]
    except:
        return ""


def get_prev_line(lines):
    try:
        return lines[-2]
    except:
        return []


def give_card(not_swap=True):
    if have_ambassador in mycards:  # give up Ambassador
        return loose_ambassador if not_swap else have_ambassador
    if have_contessa in mycards:  # give up Contessa
        return loose_contessa if not_swap else have_contessa
    if have_assassin in mycards:  # give up Assassin
        return loose_assassin if not_swap else have_assassin
    if have_duke in mycards:  # give up duke
        return loose_duke if not_swap else have_duke
    return loose_captain if not_swap else have_captain  # give up captain


action = legal_actions[0]  # failsafe
with open(filename, 'r') as file:
    all_lines = file.readlines()
    try:
        curr_line = all_lines[-1]
    except IndexError:
        curr_line = ""

obvious_actions = ['C', '~', '^', '*', '!', '$']  # borrowed from Brilliand
obvious = list(set(obvious_actions).intersection((set(legal_actions))))


otherhand = guess_opponents_hand()


# take care of easy choices
if obvious:
    action = coup if coup in obvious else obvious[0]
elif len(set(list(loosing_actions)).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card()
elif len(set([i+'\n' for i in list(loosing_actions)]).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card() + '\n'
elif len(legal_actions) == 1:
    action = legal_actions[0]
elif assassinate in legal_actions and have_assassin in mycards:  # if we can legally assassinate, we try to
    action = assassinate
elif steal in legal_actions and othercoins > 1 and have_captain in mycards:  # we steal when we can or have to prevent a killing coup
    action = steal
elif steal in legal_actions and 7 <= othercoins <= 8 and len(mycards) == 1 and have_assassin not in mycards:
    action = steal
elif block_assassinate in legal_actions and have_contessa in mycards:
    action = block_assassinate
elif block_aid in legal_actions and have_duke in mycards:
    action = block_aid
elif block_steal_cap in legal_actions and have_captain in mycards:
    action = block_steal_cap
elif block_steal_amb in legal_actions and have_ambassador in mycards:
    action = block_steal_amb
elif tax in legal_actions and have_duke in mycards:
    action = tax
elif foreign_aid in legal_actions and foreign_aid in get_prev_line(all_lines):  # opponent wouldn't foreign aid with a duke
    action = foreign_aid
elif block_aid in legal_actions:
    if loose_duke not in otherhand and len(mycards) > 1:
        action = block_aid
    else:
        action = pass_challange if pass_challange in legal_actions else "\n"


elif do_challenge in legal_actions:
    no_challenge = pass_challange if pass_challange in legal_actions else "\n"
    action = do_challenge if len(mycards) > 1 else no_challenge  # failsafe
    if get_prev_char(curr_line) == block_aid and (not loose_duke in otherhand or len(mycards) > 1):  # we don't think opponent has a duke
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif block_assassinate in legal_actions:
        if len(mycards) == 1:
            if loose_assassin in otherhand and loose_contessa not in otherhand:
                action = block_assassinate
            elif loose_assassin not in otherhand:
                action = do_challenge
            else:
                action = random.choice([block_assassinate, do_challenge])
        else:
            action = give_card()
    elif block_steal_amb in legal_actions:
        if len(mycards) > 1 and 7 <= mycoins <= 8:
            if loose_captain in otherhand:
                probs = [0.4, 0.4, 0.2]
            else:
                probs = [0.2, 0.2, 0.6]

            action = sample_from_probabilities(probs, [block_steal_amb, block_steal_cap, do_challenge])
        elif len(mycards) == 1 and len(otherhand) == 1 and 7 <= mycoins <= 8:
            action = do_challenge  # worth the risk if we defend a winning move
        else:
            action = do_challenge if len(mycards) > 1 else pass_challange  # failsafe
            # go with default

    elif get_prev_char(curr_line) == tax and loose_duke not in otherhand and len(mycards) > 1:
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif get_prev_char(curr_line) in {block_steal_cap, block_steal_amb, block_aid, block_assassinate}:
        if get_prev_char(curr_line) == block_aid:
            action = do_challenge
        elif get_prev_char(curr_line) == block_assassinate:
            if len(otherhand) == 1 and loose_contessa not in otherhand:
                action = do_challenge
        elif get_prev_char(curr_line) == block_steal_amb:
            action = pass_challange if pass_challange in legal_actions else "\n"

# other choices shall be weighted random choices
elif len(set(legal_actions).intersection({assassinate, steal, tax, income, exchange})) >= 3:
    # decide between aggro ass, aggro steal, aggro Tax, Income, Exchange
    assumed_values = [(assassinate in legal_actions) * (loose_assassin not in otherhand) * 0.1 * len(mycards) * (len(otherhand) - 1) * (mycoins >= 3),
                      (othercoins > 1) * ((othercoins > 5 * 0.3) + othercoins * 0.05) * (len(mycards) - 1) * (loose_ambassador not in otherhand),
                      0.1 * (loose_duke not in otherhand) * (len(mycards) - 1)**(len(otherhand) - 1),
                      0.3,
                      (have_ambassador in mycards) * 0.5/len(mycards)
                      ]
    normalized_probs = [float(i) / sum(assumed_values) for i in assumed_values]
    actions = [assassinate, steal, tax, income, exchange]
    action = sample_from_probabilities(normalized_probs, actions)
elif get_prev_char(curr_line) == do_challenge or get_prev_char(curr_line) == coup:
    # we lost a challenge or coup
    card = give_card()
    action = card if card in legal_actions else action
else:
    # We missed a case. This shouldn't happen. Please tell me so I can fix it!
    # Note: A failsafe always taking a legal action is in place, so please comment out the error raising after telling me :)
    raise RuntimeError("Please tell me this happened, give me the history file, comment out this line, "
                       "and replay. THANKS!")
    pass

with open(filename, "a") as history:
    history.write(str(action))

if len(mycards) > 2:
    mycards = mycards.replace(give_card(False), "", 1)
    mycards = mycards.replace(give_card(False), "", 1)
    print(mycards)

Thống kê

Biết chiến lược chiến thắng của mình, giống như con bạc, nhưng luôn tin tưởng vào xác suất tối đa thay vì lấy mẫu ngẫu nhiên từ chúng.

import sys
import random
import time

random.seed(time.time())  # lets keep it rather random

_, filename, othercoins, mycoins, mycards = sys.argv[:5]
legal_actions = sys.argv[5:]

othercoins = int(othercoins)
mycoins = int(mycoins)

income = 'I\n'

foreign_aid, coup, exchange, tax, assassinate, steal, block_aid, \
block_steal_amb, block_steal_cap, block_assassinate, \
pass_challange, do_challenge = "FCETASdacspq"


loosing_actions = "_'<=0"
loose_ambassador, loose_assassin, loose_captain, loose_contessa, loose_duke = loosing_actions
have_ambassador, have_assassin, have_captain, \
have_contessa, have_duke = "~^*!$"

actions_dict = {
    exchange: loose_ambassador, tax: loose_duke, assassinate: loose_assassin, steal: loose_captain,
    block_aid: loose_duke, block_steal_amb: loose_ambassador, block_steal_cap: loose_captain, block_assassinate: loose_contessa
}


def guess_opponents_hand():
    # get number of each card still in play and not in hand
    card_counts = [3] * 5
    card_give_up = list("_'<=0")
    with open(filename, 'r') as history:
        while True:
            line = history.readline()
            if not line:
                break
            for card in card_give_up:
                if card in line:
                    card_counts[card_give_up.index(card)] -= 1

    have_cards = list("~^*!$")

    if sum(card_counts) == 15:
        num_cards = 2
    elif sum(card_counts) == 14:
        if len(mycards) == 1:
            num_cards = 2
        else:
            num_cards = 1
    else:
        num_cards = 1

    for card in mycards:
        card_counts[have_cards.index(card)] -= 1

    # randomly sample a hand for the opponent
    card_1 = sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)
    if num_cards == 1:
        return card_1
    card_counts[card_give_up.index(card_1)] -= 1
    return card_1 + sample_from_probabilities([i / sum(card_counts) for i in card_counts], card_give_up)


def sample_from_probabilities(success_probabilities, actions):
    # statistical max, decide randomly on equivalent probabilities
    max_prob = max(success_probabilities)
    indicies = []
    idx = 0
    for i in success_probabilities:
        if i == max_prob:
            indicies.append(idx)
        idx += 1
    choice = random.choice(indicies)
    return actions[choice]


def get_prev_char(line, x=1):
    try:
        return line[-1*x]
    except:
        return ""


def get_prev_line(lines):
    try:
        return lines[-2]
    except:
        return []


def give_card(not_swap=True):
    if have_ambassador in mycards:  # give up Ambassador
        return loose_ambassador if not_swap else have_ambassador
    if have_contessa in mycards:  # give up Contessa
        return loose_contessa if not_swap else have_contessa
    if have_assassin in mycards:  # give up Assassin
        return loose_assassin if not_swap else have_assassin
    if have_duke in mycards:  # give up duke
        return loose_duke if not_swap else have_duke
    return loose_captain if not_swap else have_captain  # give up captain


action = legal_actions[0]  # failsafe
with open(filename, 'r') as file:
    all_lines = file.readlines()
    try:
        curr_line = all_lines[-1]
    except IndexError:
        curr_line = ""

obvious_actions = ['C', '~', '^', '*', '!', '$']  # borrowed from Brilliand
obvious = list(set(obvious_actions).intersection((set(legal_actions))))


otherhand = guess_opponents_hand()


# take care of easy choices
if obvious:
    action = coup if coup in obvious else obvious[0]
elif len(set(list(loosing_actions)).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card()
elif len(set([i+'\n' for i in list(loosing_actions)]).intersection(set(legal_actions))) == len(set(legal_actions)):
    action = give_card() + '\n'
elif len(legal_actions) == 1:
    action = legal_actions[0]
elif assassinate in legal_actions and have_assassin in mycards:  # if we can legally assassinate, we try to
    action = assassinate
elif steal in legal_actions and othercoins > 1 and have_captain in mycards:  # we steal when we can or have to prevent a killing coup
    action = steal
elif steal in legal_actions and 7 <= othercoins <= 8 and len(mycards) == 1 and have_assassin not in mycards:
    action = steal
elif block_assassinate in legal_actions and have_contessa in mycards:
    action = block_assassinate
elif block_aid in legal_actions and have_duke in mycards:
    action = block_aid
elif block_steal_cap in legal_actions and have_captain in mycards:
    action = block_steal_cap
elif block_steal_amb in legal_actions and have_ambassador in mycards:
    action = block_steal_amb
elif tax in legal_actions and have_duke in mycards:
    action = tax
elif foreign_aid in legal_actions and foreign_aid in get_prev_line(all_lines):  # opponent wouldn't foreign aid with a duke
    action = foreign_aid
elif block_aid in legal_actions:
    if loose_duke not in otherhand and len(mycards) > 1:
        action = block_aid
    else:
        action = pass_challange if pass_challange in legal_actions else "\n"


elif do_challenge in legal_actions:
    no_challenge = pass_challange if pass_challange in legal_actions else "\n"
    action = do_challenge if len(mycards) > 1 else no_challenge  # failsafe
    if get_prev_char(curr_line) == block_aid and (not loose_duke in otherhand or len(mycards) > 1):  # we don't think opponent has a duke
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif block_assassinate in legal_actions:
        if len(mycards) == 1:
            if loose_assassin in otherhand and loose_contessa not in otherhand:
                action = block_assassinate
            elif loose_assassin not in otherhand:
                action = do_challenge
            else:
                action = random.choice([block_assassinate, do_challenge])
        else:
            action = give_card()
    elif block_steal_amb in legal_actions:
        if len(mycards) > 1 and 7 <= mycoins <= 8:
            if loose_captain in otherhand:
                probs = [0.4, 0.4, 0.2]
            else:
                probs = [0.2, 0.2, 0.6]

            action = sample_from_probabilities(probs, [block_steal_amb, block_steal_cap, do_challenge])
        elif len(mycards) == 1 and len(otherhand) == 1 and 7 <= mycoins <= 8:
            action = do_challenge  # worth the risk if we defend a winning move
        else:
            action = do_challenge if len(mycards) > 1 else pass_challange  # failsafe
            # go with default

    elif get_prev_char(curr_line) == tax and loose_duke not in otherhand and len(mycards) > 1:
        action = do_challenge
    elif get_prev_char(curr_line) == exchange:
        action = pass_challange
    elif get_prev_char(curr_line) in {block_steal_cap, block_steal_amb, block_aid, block_assassinate}:
        if get_prev_char(curr_line) == block_aid:
            action = do_challenge
        elif get_prev_char(curr_line) == block_assassinate:
            if len(otherhand) == 1 and loose_contessa not in otherhand:
                action = do_challenge
        elif get_prev_char(curr_line) == block_steal_amb:
            action = pass_challange if pass_challange in legal_actions else "\n"

# other choices shall be weighted random choices
elif len(set(legal_actions).intersection({assassinate, steal, tax, income, exchange})) >= 3:
    # decide between aggro ass, aggro steal, aggro Tax, Income, Exchange
    assumed_values = [(assassinate in legal_actions) * (loose_assassin not in otherhand) * 0.1 * len(mycards) * (len(otherhand) - 1) * (mycoins >= 3),
                      (othercoins > 1) * ((othercoins > 5 * 0.3) + othercoins * 0.05) * (len(mycards) - 1) * (loose_ambassador not in otherhand),
                      0.1 * (loose_duke not in otherhand) * (len(mycards) - 1)**(len(otherhand) - 1),
                      0.3,
                      (have_ambassador in mycards) * 0.5/len(mycards)
                      ]
    normalized_probs = [float(i) / sum(assumed_values) for i in assumed_values]
    actions = [assassinate, steal, tax, income, exchange]
    action = sample_from_probabilities(normalized_probs, actions)
elif get_prev_char(curr_line) == do_challenge or get_prev_char(curr_line) == coup:
    # we lost a challenge or coup
    card = give_card()
    action = card if card in legal_actions else action
else:
    # We missed a case. This shouldn't happen. Please tell me so I can fix it!
    # Note: A failsafe always taking a legal action is in place, so please comment out the error raising after telling me :)
    raise RuntimeError("Please tell me this happened, give me the history file, comment out this line, "
                       "and replay. THANKS!")
    pass

with open(filename, "a") as history:
    history.write(str(action))

if len(mycards) > 2:
    mycards = mycards.replace(give_card(False), "", 1)
    mycards = mycards.replace(give_card(False), "", 1)
    print(mycards)


1
Chương trình này gặp sự cố trên một tệp trống khi nó đi trước. Khi nó đi thứ hai, nó gặp sự cố với một thông báo như : Traceback (most recent call last): File "gambler.py", line 94, in <module> otherhand = guess_opponents_hand() File "gambler.py", line 61, in guess_opponents_hand card_counts[card_give_up.index(card_1)] -= 1 ValueError: ['_'] is not in list.
Tím P

đã có thể sửa lỗi đó. xin lỗi, tôi đã đăng nó một cách vội vàng Tôi chắc chắn sẽ kiểm tra nó với trọng tài của bạn cho đến ngày mai, nhưng một lỗi rõ ràng đã được sửa. xin lỗi lần nữa.
jaaq

1
Tin vui, trao đổi của Gambler hoạt động trên máy của tôi! Nó vẫn gặp sự cố nếu đối thủ của nó cố gắng Hỗ trợ nước ngoài và nó không có Công tước, nhưng nó đã được thêm vào bảng xếp hạng.
Tím P

1
@jaaq Nó vẫn bị tịch thu nếu đối thủ của nó cố gắng Viện trợ nước ngoài và nó không có Công tước; nó cần phải trả lời rằng với một lượt đi, không phải là kết thúc.
Brilliand

1
@jaaq Tôi đã sửa lỗi mà Brilliand đề cập và thêm Statistician vào bảng xếp hạng. Khi các mục của bạn bị ám sát với một thẻ còn lại, chúng bị mất bằng cách viết \nthay vì thẻ mà chúng muốn từ bỏ. Trong tình huống như vậy, tốt hơn là chiến đấu trở lại với một khối hoặc thử thách. Nếu Gambler thắng 5 game mà nó bị mất như thế này, thì nó sẽ chiếm vị trí đầu tiên.
Tím P
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.