Trao đổi voi trắng


11

Đó là Giáng sinh vào tháng 7, vì vậy cách nào tốt hơn để ăn mừng hơn là trao đổi quà tặng voi trắng ảo!

Đối với thử thách King of the Hill này, bạn phải tạo một bot chơi trong mô phỏng trao đổi Voi Trắng , cố gắng có được món quà có giá trị cao nhất có thể.

Luật chơi

  • Trò chơi sẽ được chơi qua nhiều vòng, mỗi vòng được tạo thành từ một số lượt khác nhau.
  • Thiết lập vòng : Sẽ có nhiều quà như người chơi trong trò chơi, mỗi người được định giá ngẫu nhiên trong phạm vi [0 ... 1), với giá trị này không xác định cho đến khi hiện tại được "mở". Người chơi sẽ được sắp xếp theo thứ tự ngẫu nhiên trong hàng đợi. Người chơi đầu tiên sẽ xuất hiện từ phía trước hàng đợi.
  • Khi đến lượt của người chơi, họ có thể mở một món quà hoặc ăn cắp món quà của người chơi khác, chuyển qua cho người chơi có món quà bị đánh cắp.
    • Mỗi món quà có thể bị đánh cắp tới 3 lần.
    • Bạn không thể đánh cắp từ người chơi vừa đánh cắp bạn.
    • Mỗi người chơi chỉ có thể có một món quà tại một thời điểm.
  • Sau khi một món quà được mở ra, chơi tiến tới người chơi tiếp theo xuất hiện từ phía trước hàng đợi. Đây sẽ là người chơi tiếp theo theo thứ tự lần lượt chưa có lượt.
  • Kết thúc vòng : Khi tất cả các món quà đã được mở, vòng kết thúc và giá trị của món quà mà mỗi người chơi nắm giữ sẽ được thêm vào điểm của người chơi đó. Một vòng chơi mới bắt đầu, với mỗi người chơi hiện không có quà và thứ tự người chơi bị xáo trộn.
  • Kết thúc trò chơi : Trò chơi sẽ kết thúc khi có ít nhất một người chơi đạt được 100 500 điểm, với chiến thắng được trao cho người chơi có tổng giá trị quà tặng cao nhất.

Mã hóa

Tất cả các đệ trình phải tương thích với Python 3.7. Bạn phải viết một lớp kế thừa trực tiếp WhiteElephantBot. Ví dụ:

class FooBot(WhiteElephantBot):
    # Your implementation here

Bạn có thể cung cấp một __init__phương thức (lấy một đối số name) trong lớp bot của bạn, mà phải gọi super().__init__(name). Lớp của bạn phải có một take_turnphương thức mong đợi các đối số sau theo thứ tự này:

  • players: Danh sách tên người chơi, theo thứ tự lần lượt, của tất cả người chơi chưa có quà.
  • presents: Một từ điển ánh xạ tên người chơi thành 2 tuple chứa giá trị hiện tại mà người chơi đó nắm giữ và số lần hiện tại đã bị đánh cắp. Điều này sẽ chỉ bao gồm những người chơi khác hiện đang giữ quà.
  • just_stole: Nếu hành động cuối cùng được thực hiện là đánh cắp, đây sẽ là tên của người chơi vừa đánh cắp. Nếu không, nó sẽ được None.

Mỗi đối số sẽ là bất biến hoặc một đối tượng mới để việc biến đổi bất kỳ trong số chúng sẽ không có ảnh hưởng đến trò chơi. Bạn có thể giữ một bản sao của bất kỳ đối số nào nếu bạn mong muốn.

Một giá trị mẫu cho presents:

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

take_turnPhương pháp của bạn sẽ trả lại tên của người chơi mà bạn muốn đánh cắp hoặc Noneđể mở một món quà. Nếu nó phát sinh một ngoại lệ, trả về một cái gì đó không phải là strhoặc Nonehoặc tên của một người chơi mà bạn không thể đánh cắp, bạn sẽ mở một món quà theo mặc định.

Nhà xây dựng của bạn sẽ được gọi vào đầu mỗi vòng, vì vậy bạn không cần nhớ trạng thái từ vòng này sang vòng khác.

Bằng cách kế thừa từ WhiteElephantBot, bạn sẽ có quyền truy cập vào một steal_targetsphương thức sẽ đưa quà ra lệnh just_stolevà trả lại danh sách tên người chơi bạn có thể đánh cắp.

Bất kỳ mô-đun nào mà kịch bản của bạn cần phải được nhập ở đầu mục nhập của bạn.

Lái thử

Trình điều khiển thử nghiệm có thể được tìm thấy ở đây . Bạn không cần đưa from white_elephant import WhiteElephantBotvào câu trả lời đã đăng của mình, tuy nhiên một mô-đun cục bộ sẽ cần phải làm điều đó.

Đối thủ cạnh tranh cơ bản

  • Ngẫu nhiên : Chọn ngẫu nhiên để mở một món quà mới hay để ăn cắp, với mục tiêu ăn cắp được chọn ngẫu nhiên.
  • Tham lam : đánh cắp món quà giá trị nhất có thể bị đánh cắp. Nếu không có món quà nào có thể bị đánh cắp, hãy mở một món quà.
  • Nice : Luôn mở một món quà mới. Không bao giờ đánh cắp.

Quy tắc bổ sung

  • Bạn có trách nhiệm bắt tất cả các ngoại lệ. Nếu lớp của bạn không bắt được một ngoại lệ, nó sẽ bị loại. Ngoài ra, vui lòng không bắt bàn phím.
  • Không sử dụng tệp hoặc phương pháp khác để bỏ qua việc không thể lưu trạng thái giữa các trò chơi. Ví dụ, bạn không thể lưu trạng thái mạng thần kinh vào một tệp giữa chừng.
  • Bot của bạn phải được chứa trong mã lớp và các hằng số liên quan.
  • Bạn chỉ có thể sử dụng nhập thư viện tiêu chuẩn.
  • Không có yêu cầu thực hiện nghiêm ngặt. Hãy hợp lý và thận trọng. Nếu hiệu suất trở thành một vấn đề, tôi bảo lưu quyền thêm giới hạn thời gian.
  • Một mục nhập mỗi người. Nếu bạn gửi nhiều mục, bot của bạn có thể không hoạt động cùng nhau. Bây giờ tôi sẽ cho phép nhiều mục nhập cho mỗi người, mặc dù tôi có thể sửa lại nó sau nếu nó trở thành vấn đề.
  • Đây là một cuộc thi mở không có ngày kết thúc khác biệt. Nó sẽ được chạy lại bất cứ lúc nào tôi có thể khi có những thay đổi đáng kể.

EDIT1: Thay đổi điểm chiến thắng từ 100 đến 500 để thứ hạng phù hợp hơn. Trình điều khiển thử nghiệm có một lỗi mới và cũng phản ánh sự thay đổi điểm số chiến thắng.

EDIT2: Làm rõ lưu ý về nhập khẩu bắt buộc.


Bảng xếp hạng (kể từ ngày 8 tháng 8 năm 2018)

  1. MẫuBot (500.093)
  2. LastMinuteBot (486.163)
  3. RobinHood (463.160)
  4. OddTodd (448.825)
  5. Tham lam (438.520)
  6. SecondPlaceBot (430.598)
  7. NgưỡngBot (390.480)
  8. Con bạc (313.362)
  9. NiceBot (275.536)
  10. RandomBot (256.172)
  11. GoodSamaritan (136.298)

Có thể có bất kỳ số lượng đánh cắp liên tiếp? Khi tôi đã chơi, thường có giới hạn 2 lần đánh cắp liên tiếp hoặc thứ gì đó, và người thứ ba từ đó sẽ phải mở một. Điều này ngăn chặn cùng một món quà bị đánh cắp nhiều hơn một lần mỗi lượt.
mbomb007

@ mbomb007 Có. Trộm cắp chuỗi là không giới hạn, ngoại trừ theo các quy tắc khác làm cho một số món quà nhất định miễn nhiễm với việc ăn cắp: mỗi món quà chỉ có thể bị đánh cắp 3 lần và bạn không thể đánh cắp từ người chơi vừa lấy trộm của bạn.
Beefster

Bạn có thể ăn cắp một món quà và sau đó ăn cắp lại bản gốc bạn có?
Erik the Outgolfer 25/07/18

@EriktheOutgolfer: có, miễn là có một ngã rẽ khác ở giữa. Bạn không thể đánh cắp lại ngay lập tức sau khi món quà của bạn bị đánh cắp.
Beefster

1
Trao đổi Yankee!? Điều gì tiếp theo, một bữa tiệc sinh nhật được chia sẻ?
ngm

Câu trả lời:


3

LastMinuteBot

(Rất cảm ơn @Mnemonic về bộ xương của mã, vì tôi hầu như không biết Python.)

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

        target = None

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

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

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

Tận dụng thực tế là quà tặng không thể bị đánh cắp nhiều hơn ba lần, hãy tự đánh cắp lần thứ ba nếu bạn tìm thấy một món quà có giá trị cao và hầu hết các món quà đã được mở.


Đơn giản nhưng đẹp đẽ
r_j

2

Odd

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

        targets = self.steal_targets(presents, just_stole)

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

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

        else:
            return None

Ăn cắp món quà tốt nhất mà anh ta có thể, nhưng không muốn trở thành người thứ hai ăn cắp một món quà, bởi vì nếu nó bị đánh cắp từ anh ta, anh ta không thể lấy lại.


Lỗi cú pháp trên dòng 11. Bạn cần một ==thay vì =trong phần hiểu danh sách của bạn.
Beefster

Đã sửa, cảm ơn! Đừng sử dụng Python nhiều.
brian_t

1

SecondPlaceBot

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

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

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

Mọi người sẽ chiến đấu vì món quà giá trị nhất. Món quà tốt nhất tiếp theo gần như là tốt, nhưng ít có khả năng bị đánh cắp.


1

Ngưỡng

import random

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

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

        if not targets:
            return None

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

Chúng tôi không thực sự quan tâm đến việc nhận được món quà tốt nhất , chỉ cần một cái gì đó đủ tốt . Chừng nào có thứ gì đó đáng để ăn cắp, chúng ta sẽ làm điều đó.


1

MẫuBot

import random

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

Chạy 2000 mô phỏng với mỗi người chơi hành động tham lam và chọn hành động tốt nhất.


Bot này làm gì chính xác?
Beefster

@Beefster Chạy 2000 trò chơi ngẫu nhiên với mỗi người chơi hành động tham lam và chọn nước đi với số điểm cuối cùng trung bình cao nhất.
user1502040

Lỗi tên. Bạn cần nhập ngẫu nhiên.
Beefster

1

Người hùng Robin Hood

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

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

Ăn cắp từ những người giàu không kiếm được quà của họ


Bạn có một lỗi thụt lề.
Beefster

0

GoodSamaritan

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

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

Hãy cho những người không may mắn một cơ hội may mắn khác


0

Con bạc

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

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

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

Con bạc nghiện, anh ta cố gắng trở thành người chơi cuối cùng, sau đó anh ta đánh bạc vào một món quà mới để đánh bại tất cả những người chơi khác.


0

Top3Bot

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

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

        targets = self.steal_targets(presents, just_stole)

        if players:
            targets += None

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


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

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

Bot này không cố gắng để có được món quà tốt nhất có thể, nhưng cố gắng để có được một món quà có giá trị> = (n-3) / n, trong đó n là số lượng quà tặng. Trong hầu hết các trường hợp, sẽ có những món quà có giá trị rất lớn và Top3Bot sẽ cố gắng để có được một trong những thứ này, nhưng anh ấy không thực sự quan tâm đến những thứ anh ấy nhận được.


bạn __init__đang thiếu selflập luận của nó
Beefster
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.