Magic: the Gathering là một trò chơi đánh bài trong đó, trong số những thứ khác, người chơi chơi bài đại diện cho sinh vật, sau đó có thể tấn công người chơi khác hoặc phòng thủ trước các cuộc tấn công của người chơi khác bằng cách chặn.
Trong thử thách chơi gôn mã này, chương trình của bạn sẽ ở vị trí của một người chơi Magic quyết định cách chặn trong chiến đấu.
Mỗi sinh vật có hai thuộc tính có liên quan: Sức mạnh và độ dẻo dai. Sức mạnh của một sinh vật là lượng sát thương mà nó có thể gây ra trong một trận chiến, và độ dẻo dai của nó là lượng sát thương cần thiết để tiêu diệt nó. Sức mạnh luôn luôn ít nhất là 0 và độ dẻo dai luôn luôn ít nhất là 1.
Trong trận chiến trong Magic, người chơi đến lượt mình tuyên bố một số sinh vật của họ sẽ tấn công đối thủ. Sau đó, người chơi khác, được gọi là người chơi phòng thủ, có thể chỉ định sinh vật của họ là người chặn. Một sinh vật có thể chỉ chặn một sinh vật trong mỗi trận chiến, nhưng nhiều sinh vật có thể chặn cùng một sinh vật.
Sau khi các công cụ chặn được tuyên bố, người chơi tấn công quyết định, đối với mỗi sinh vật tấn công bị chặn, làm thế nào để phân phối thiệt hại (bằng với sức mạnh của nó) mà sinh vật đó gây ra cho các sinh vật chặn nó.
Sau đó, thiệt hại được xử lý. Mỗi sinh vật gây sát thương tương đương với sức mạnh của nó. Tấn công các sinh vật đã bị chặn gây sát thương như đã giải thích ở trên. Sinh vật tấn công không bị chặn gây sát thương cho người chơi phòng thủ. Chặn sinh vật gây sát thương cho sinh vật mà chúng chặn. Sinh vật thuộc về người chơi phòng thủ không chặn gây sát thương. (Sinh vật không bắt buộc phải chặn.)
Cuối cùng, bất kỳ sinh vật nào gây sát thương bằng hoặc lớn hơn độ dẻo dai của nó đều bị phá hủy, và bị loại khỏi chiến trường. Bất kỳ lượng sát thương nào nhỏ hơn độ dẻo dai của sinh vật đều không có tác dụng.
Đây là một ví dụ về quy trình này:
Một sinh vật có sức mạnh P và độ dẻo dai T được thể hiện là P/T
Attacking:
2/2, 3/3
Defending player's creatures:
1/4, 1/1, 0/1
Defending player declares blockers:
1/4 and 1/1 block 2/2, 0/1 does not block.
Attacking player distributes damage:
2/2 deals 1 damage to 1/4 and 1 damage to 1/1
Damage is dealt:
2/2 takes 2 damage, destroyed.
3/3 takes 0 damage.
1/1 takes 1 damage, destroyed.
1/4 takes 1 damage.
0/1 takes 0 damage.
Defending player is dealt 3 damage.
Người chơi phòng thủ có 3 mục tiêu trong chiến đấu: Tiêu diệt sinh vật của đối thủ, bảo tồn sinh vật của chính mình và bị gây sát thương ít nhất có thể. Ngoài ra, những sinh vật có sức mạnh và sự dẻo dai hơn có giá trị hơn.
Để kết hợp những điều này thành một biện pháp duy nhất, chúng tôi sẽ nói rằng điểm số của người chơi phòng thủ từ một trận chiến bằng tổng sức mạnh và sự dẻo dai của các sinh vật còn sống của họ, trừ đi sức mạnh và sự dẻo dai của các sinh vật còn sống của đối thủ, trừ đi một một nửa lượng sát thương gây ra cho người chơi phòng thủ. Người chơi phòng thủ muốn tối đa hóa điểm số này, trong khi người chơi tấn công muốn tối thiểu hóa nó.
Trong trận chiến hiển thị ở trên, điểm số là:
Defending player's surviving creatures:
1/4, 0/1
1 + 4 + 0 + 1 = 6
Attacking player's surviving creature:
3/3
3 + 3 = 6
Damage dealt to defending player:
3
6 - 6 - 3/2 = -1.5
Nếu người chơi phòng thủ hoàn toàn không bị chặn trong trận chiến được mô tả ở trên, điểm số sẽ là
8 - 10 - (5/2) = -4.5
Sự lựa chọn tối ưu cho người chơi phòng thủ sẽ là chặn 2/2
với 1/1
và 1/4
và chặn 3/3
với 0/1
. Nếu họ đã làm như vậy, chỉ 1/4
và 3/3
sẽ sống sót, và không có thiệt hại nào sẽ được xử lý cho người chơi phòng thủ, tạo ra điểm số
5 - 6 - (0/2) = -1
Thử thách của bạn là viết một chương trình sẽ đưa ra lựa chọn chặn tối ưu cho người chơi phòng thủ. "Tối ưu" có nghĩa là lựa chọn tối đa hóa điểm số, cho rằng đối thủ phân phối thiệt hại theo cách giảm thiểu điểm số, dựa trên cách bạn chặn.
Đây là một maximin: Điểm tối đa trên các phân phối thiệt hại giúp giảm thiểu điểm số cho mỗi kết hợp chặn.
Đầu vào: Đầu vào sẽ bao gồm hai danh sách 2 tuple, trong đó mỗi 2 tuple có dạng (Power, Toughness). Danh sách đầu tiên sẽ chứa sức mạnh và độ dẻo dai của từng sinh vật tấn công (bạn là sinh vật của đối thủ). Danh sách thứ hai sẽ chứa sức mạnh và sự dẻo dai của mỗi sinh vật của bạn.
Các bộ và danh sách có thể được trình bày theo bất kỳ định dạng thuận tiện nào, chẳng hạn như:
[[2, 2], [3, 3]]
[[1, 4], [1, 1], [0, 1]]
Đầu ra: Đầu ra sẽ bao gồm một loạt 2 tuple, ở dạng (sinh vật chặn, sinh vật bị chặn) - nghĩa là, một trong những sinh vật của bạn theo sau là một trong những sinh vật của họ. Các sinh vật sẽ được giới thiệu bởi chỉ mục của chúng trong danh sách đầu vào. Các chỉ mục có thể là 0 hoặc 1 được lập chỉ mục. Một lần nữa, bất kỳ định dạng thuận tiện. Bất kỳ thứ tự là tốt. Ví dụ: kịch bản chặn tối ưu từ phía trên, với đầu vào ở trên, có thể được biểu diễn dưới dạng:
[0, 0] # 1/4 blocks 2/2
[1, 0] # 1/1 blocks 2/2
[2, 1] # 0/1 blocks 3/3
Ví dụ:
Input:
[[2, 2], [3, 3]]
[[1, 4], [1, 1], [0, 1]]
Output:
[0, 0]
[1, 0]
[2, 1]
Input:
[[3, 3], [3, 3]]
[[2, 3], [2, 2], [2, 2]]
Output:
[1, 0]
[2, 0]
or
[1, 1]
[2, 1]
Input:
[[3, 1], [7, 2]]
[[0, 4], [1, 1]]
Output:
[1, 0]
or
[0, 0]
[1, 0]
Input:
[[2, 2]]
[[1, 1]]
Output:
(No output tuples).
Đầu vào và đầu ra có thể qua STDIN, STDOUT, CLA, chức năng đầu vào / trở lại vv sơ hở tiêu chuẩn được áp dụng. Đây là code-golf: mã ngắn nhất tính theo byte thắng.
Để làm rõ thông số kỹ thuật và cung cấp các ý tưởng ban đầu, pastebin này cung cấp một giải pháp tham chiếu trong Python. Các best_block
chức năng là một giải pháp mẫu để thử thách này, và chạy chương trình sẽ cung cấp đầu vào và đầu ra dài hơn.