Tìm di chuyển tối ưu nim


8

Tro choi

Nim là một trò chơi chiến lược toán học, trong đó 2 người chơi thay phiên nhau lấy các vật phẩm từ các đống khác nhau. Đến lượt bạn, bạn phải lấy ít nhất một vật phẩm và bạn có thể lấy bao nhiêu tùy thích, miễn là bạn chỉ lấy từ một đống. Người chơi lấy vật phẩm cuối cùng sẽ thắng! Đây là một trò chơi giải quyết. Trước khi tôi đi vào chiến lược, bạn có thể thử chơi trực tuyến tại đây .

Chiến lược

Chiến lược chiến thắng được giải thích rất rõ ràng và đơn giản tại đây . Tôi sẽ giải thích nó bằng cách sử dụng một chút thuật ngữ kỹ thuật. Cách để chiến thắng trò chơi này là luôn lấy càng nhiều vật phẩm càng tốt để tổng nhị phân-số luôn luôn bằng 0. Hãy xem xét bảng sau:

         *
       * *
     * * *
   * * * *
 * * * * *
 1 2 3 4 5

Để tìm tổng nhị phân-số của bảng này, bạn phải:

  1. Chuyển đổi số trong mỗi hàng thành nhị phân. Vậy ta có 001, 010, 011, 100 và 101.

  2. Thêm tất cả các số với nhau, và bỏ qua bất kỳ mang.

     001
     010
     011
     100
    +101
    ----
     001
    

    Bạn cũng có thể bitwise-xor mỗi số và điều này sẽ đạt được kết quả tương tự.

Bây giờ, nếu tổng trong cấu hình hiện tại này là 001, thì đây chưa phải là một bảng chiến thắng. Nhưng bạn có thể làm cho nó một bảng chiến thắng! Nếu chúng tôi lấy một mục trong các cột 1, 3 hoặc 5, tổng sẽ là 0. Đây là một bảng chiến thắng, có nghĩa là, với điều kiện bạn không phạm sai lầm, người chơi tiếp theo sẽ di chuyển sẽ thua. Vì vậy, bạn phải luôn luôn kết thúc lượt của mình với một bảng chiến thắng. Hãy nói rằng bạn lấy một mục ra khỏi cột 5. Bây giờ bảng trông như thế này:

       * *
     * * *
   * * * *
 * * * * *
 1 2 3 4 5

Miễn là bạn không làm hỏng, bạn có một chiến thắng được đảm bảo. Không có gì đối thủ của bạn có thể làm để ngăn chặn bạn. Hãy nói rằng anh ta lấy tất cả các mục từ cột 5.

       *
     * *
   * * *
 * * * *
 1 2 3 4 5

Bạn sẽ đi đâu tiếp theo? Đừng cuộn xuống và cố gắng tự mình tìm ra.


Ngay bây giờ, tổng là 100. Di chuyển tốt nhất (và chỉ di chuyển chiến thắng) sẽ là lấy tất cả mọi thứ từ cột 4. Điều đó sẽ rời khỏi bảng như thế này:

     * 
   * * 
 * * * 
 1 2 3 4 5

và tổng như thế này

 001
 010
+011
----
 000

điều đó có nghĩa là bạn đang ở trong một bảng chiến thắng! Yay!

Các thách thức

Bạn phải viết một chương trình hoặc chức năng, được đưa ra một bảng nim, sẽ trả lại một nước đi chiến thắng, hoặc một giá trị chim ưng nếu không có nước cờ chiến thắng.

Đầu vào của bạn:

  • Sẽ là định dạng danh sách ngôn ngữ gốc của bạn, trong đó mỗi mục trong danh sách tương ứng với số lượng mục trong một cột nhất định. Ví dụ: đầu vào {4, 2, 1, 0, 3} tương ứng với bảng nim sau:

    *
    *           *
    *  *        *
    *  *  *     *
    1, 2, 3, 4, 5
    
  • (tùy chọn) Số lượng hàng. (Đối với các ngôn ngữ như C / C ++, nơi mà điều này không được biết đến từ chính danh sách.)

Đầu ra của bạn:

  • Có thể đi đến STDOUT hoặc được trả về từ chức năng

  • Phải là hai số, 1) cột chúng tôi đang xóa (Hãy nhớ rằng các cột được lập chỉ mục 0) và 2) số lượng mục cần xóa khỏi hàng đó. Đây có thể là một mảng gồm 2 mục, một chuỗi gồm hai số, v.v ... Hãy nhớ rằng câu trả lời có thể dài hơn 2 chữ số, do đó, trả về chuỗi "111" là không hợp lệ vì điều này không rõ ràng nếu điều này không rõ ràng có nghĩa là "Xóa một mục khỏi cột mười một" hoặc "Xóa mười một mục khỏi cột một". "1,11" hoặc "11,1" đều được chấp nhận.

  • Nếu không có câu trả lời, trả lại hoặc in một giá trị giả. Nếu ngôn ngữ của bạn chỉ có thể trả về một loại biến (một lần nữa, như C / C ++), một số âm cho cột hoặc 0 hoặc ít hơn cho số cần loại bỏ sẽ là giá trị falsey chấp nhận được.

  • Nếu số cột hoặc số cần loại bỏ quá lớn, đây được coi là đầu ra không hợp lệ.

Đầu vào / Đầu ra mẫu

[1, 2, 3, 4, 5]---> [0, 1]hoặc [4, 1]hoặc[2, 1]

[1, 3, 5, 6]---> [0, 1]hoặc [1, 1]hoặc[2, 1]

[1, 2, 0, 0, 5] ---> [4, 2]

[1, 2, 3] ---> ERROR

Nếu bạn chọn thực hiện một chức năng thay vì chương trình đầy đủ, thì bạn phải viết một chương trình đầy đủ để thể hiện chức năng đó trong thực tế. Điều này sẽ không được tính vào điểm số đầy đủ của bạn. Ngoài ra, các chương trình dự kiến ​​sẽ chạy trong một khoảng thời gian hợp lý. Tôi không có kế hoạch nhập bất kỳ đầu vào quá lớn nào, miễn là chương trình của bạn không thực hiện tìm kiếm vũ phu trên toàn bộ cây trò chơi, bạn sẽ ổn thôi.

Như thường lệ, đây là môn đánh gôn, do đó, các vòng lặp tiêu chuẩn được áp dụng và các câu trả lời được tính bằng byte.

Bảng xếp hạng

Dưới đây là một Stack Snippet để tạo cả bảng xếp hạng thông thường và tổng quan về người chiến thắng theo ngôn ngữ.

Để đảm bảo rằng câu trả lời của bạn hiển thị, vui lòng bắt đầu câu trả lời của bạn bằng một tiêu đề, sử dụng mẫu Markdown sau:

# Language Name, N bytes

nơi Nlà kích thước của trình của bạn. Nếu bạn cải thiện điểm số của mình, bạn có thể giữ điểm số cũ trong tiêu đề, bằng cách đánh chúng qua. Ví dụ:

# Ruby, <s>104</s> <s>101</s> 96 bytes


Chúng ta có thể giả sử rằng danh sách đầu vào chứa ít nhất một số dương không?
Jakube

@Jakube có, bạn có thể.
James

Câu trả lời:


3

Pyth, 33 22 21 20 19 byte

eS.e*<JxxFQbb,k-bJQ

Bạn có thể thử nó trong trình biên dịch trực tuyến ở đây.

Cảm ơn Jakube vì đã xóa 12 byte và Maltysen vì đã xóa một byte bổ sung!

Điều này in một động thái chiến thắng từ vị trí hiện tại. Nếu không có nước cờ chiến thắng, nó sẽ không in bất cứ thứ gì.

Tôi đã sử dụng thuật toán trên wikipedia . Đây là sự cố:

  .e              Q    While enumerating every element in the input:
      J                    Assign variable J to:
        xFQ                 Every element of the input bitwise xor'ed together,
       x   b                bitwise xor'ed with the current element of the input
             ,             Create a tuple containing:
              k             The index of the current element, and
               -bJ          the difference between the current element and J
    *<J     b              Put that tuple into a list if J < b, otherwise put an empty tuple
 S                     Sort the list
e                      Print the last element of the list

3

Bình thường, 23 byte

eSs.em*,kd!xxxFQb-bdSbQ

Dùng thử trực tuyến: Trình diễn

Điều này lặp đi lặp lại trên tất cả các di chuyển có thể và thậm chí không sắp xếp. Do đó, nó có độ phức tạp về thời gian và độ phức tạp của O(N*log(N))bộ nhớ O(N), trong đó Ntổng của danh sách đầu vào hoặc số lượng mục.

Do độ phức tạp của thời gian xấu, đây có thể không phải là một câu trả lời hợp lệ. Mặc dù nó giải quyết tất cả các trò chơi, nhưng bạn có thể chơi trong đời thực với các vật thể thực ngay lập tức.

Giải trình:

                          implicit: Q = input list
   .e                 Q   map each (index k, item b) of Q to:
     m              Sb      map each d of [1, 2, ..., b] to:
       ,kd                      the pair (k, d)
      *                       multiplied by
             xFQ                xor of all numbers in Q
            x   b               xor with b
           x     -bd            xor with b-d
          !                     not (1 if xor==0 else 0)

So the input [1, 2, 0, 0, 5] gives [[[]], [[], []], [], [], [[], [4, 2], [], [], []]]

  s                       add all lists to one big list
 S                        sort

Now it looks like this: [[], [], [], [], [], [], [], [4, 2]]

e                         pick the last element and print

3

CJam, 21 20 byte

Đã lưu một byte so với phiên bản gốc và xử lý lỗi cũng hoạt động ngay bây giờ:

l~__:^f^.-_:g1#_@=S\

Dùng thử trực tuyến

Đầu vào là một mảng CJam, ví dụ:

[1 2 3 4 5]

Nếu không có giải pháp nào được tìm thấy, nó sẽ in -1 0, đáp ứng sự hiểu biết của tôi về các yêu cầu đầu ra.

Giải trình:

l~      Get input.
__      Make two copies for following operations.
:^      Reduce with xor operator, producing xor of all columns.
f^      xor all input values with the result. For each column, this calculates
        the value that the column would have to change to make the overall
        xor zero. Consider this the "target values".
.-      Subtract the target values from the input values.
_:g     Per element signum of difference between target value and input value.
1#      Find index with value 1, which is the first positive value.
_@=     Get the value at the index.
S\      Put a space between index and value.

1

Hồng ngọc, 95

->(a){r=[false,c=0]
a.each{|e|c^=e}
a.each_index{|i|(n=a[i]-(c^a[i]))>0&&n>r[1]?(r=[i,n]):0}
r}

Tôi đã viết 2 chức năng ẩn danh riêng biệt. Cái đầu tiên, được gán cho ftrong chương trình bên dưới, in tất cả các giải pháp và cái thứ hai g(tương ứng với điểm số ở trên, vì nó vừa ngắn hơn và phù hợp hơn với thông số kỹ thuật) chỉ trả về giải pháp yêu cầu loại bỏ số lớn nhất.

trong cả hai trường hợp, tổng chữ số được tính tổng bằng c. Sau đó, mảng được lặp lại và biểu thức n=a[i]-(c^a[i])được sử dụng để tính toán số lượng bộ đếm cần loại bỏ (rõ ràng điều này chỉ có thể được thực hiện nếu vượt quá 0).

trong f, tất cả các giải pháp có thể được in (nếu cđược tìm thấy 0, errorđược in mà không lặp.) Tôi ngạc nhiên khi thấy các cọc khác nhau có thể yêu cầu loại bỏ số lượng bộ đếm khá khác nhau.

trong gmảng đầu ra rchỉ được cập nhật nếu số lượng bộ đếm được loại bỏ vượt quá số trước đó. mảng r = [pile index, number to be removed]được trả về. Nếu không có giải pháp, số lượng bộ đếm cần loại bỏ luôn bằng 0, rkhông đổi và giá trị ban đầu của r = [false,0]được trả về.

Tiết kiệm nhỏ là có thể nếu falsecó thể được thay đổi thành ví dụ "!"và nếu bất kỳ giải pháp hợp lệ thay vì giải pháp lớn nhất có thể được trả lại (bằng cách xóa &&n>r[1].)

Định dạng trong chương trình thử nghiệm

f=->(a){
  c=0
  a.each{|e|c^=e}
  c<1?(p "error"):(a.each_index{
     |i|(n=a[i]-(c^a[i]))>0?(p"#{i},#{n}"):0
   })
}

g=->(a){
  r=[false,c=0]
  a.each{|e|c^=e}
  a.each_index{
     |i|(n=a[i]-(c^a[i]))>0&&n>r[1]?(r=[i,n]):0
  }
  r
}

#Change the following two lines according to the number of values youj want to use for testing.
t=[rand(15),rand(15),rand(15),rand(15)] #Generate some random numbers for testing.
t=[gets.to_i,gets.to_i,gets.to_i]       #User input. Delete this line if you want to test with random numbers.
print t,"\n"

f.call(t)
puts g.call(t)

Trên thực tế, vì r[1]luôn luôn ít nhất là 0, tôi nghĩ >0&&n>r[1]có thể rút ngắn xuống>r[1]
Level River St


0

JavaScript (ES6), 54 byte

Trả về cặp [column, number]hoặc sai

a=>a.some((n,i)=>r=(n-=n^eval(a.join`^`))>0&&[i,n])&&r

Hãy thử trực tuyến!

Đã bình luận

a =>                        // a[] = input array
  a.some((n, i) =>          // for each value n at position i in a[]:
    r = (                   //   save the result of the iteration in r
      n -=                  //   subtract from n:
        n ^ eval(a.join`^`) //     n XOR (all values in a[] XOR'ed together)
    ) > 0                   //   if the above value is positive:
    && [i, n]               //     yield the solution [i, n] and exit the some() loop
                            //   (otherwise: yield false and go on with the next value)
  ) && r                    // end of some(); return r
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.