Xây dựng một AI hoàn hảo cho trò chơi 15


8

Trong trò chơi 15, hai người chơi lần lượt chọn các số từ 1 đến 9 (không chọn bất kỳ số nào mà một trong hai người chơi đã chọn). Người chơi thắng nếu anh ta hoặc cô ta có ba số cộng tối đa 15. Nếu tất cả các số đã được chọn và không có sự kết hợp nào của một trong hai người chơi thêm tối đa 15, thì trò chơi là hòa.

Nhiệm vụ của bạn là xây dựng một chức năng có trạng thái trò chơi 15 (được thể hiện dưới bất kỳ hình thức nào bạn thích) và trả về số nào sẽ di chuyển tiếp theo, sẽ hoạt động như một AI để chơi trò chơi với người chơi khác. Bạn có thể cho rằng vị trí đó là hợp pháp (không có người chơi nào có nhiều hơn một số so với người chơi khác và không có người chơi nào có ba số cộng với tối đa 15).

AI phải hoàn hảo - nghĩa là, nếu nó được trao một vị trí chiến thắng, nó phải buộc một chiến thắng và nếu nó được đưa ra một vị trí không thua (một vị trí mà đối thủ của nó không có chiến lược chiến thắng), thì nó không được phép Đối thủ để cho nó một vị trí thua (điều này là có thể, vì 15 là một trò chơi đã được giải quyết).

Mã ngắn nhất sẽ thắng.

(lưu ý: Tôi sẽ chấp nhận câu trả lời ngắn nhất hiện tại và thay đổi nếu câu trả lời ngắn hơn xuất hiện.)


Tôi có hiểu chính xác chúng ta được phép thua nếu chúng ta vào một vị trí có thể chiến thắng mà AI của chúng ta không thể có được không?
John Dvorak

Vâng, đó là chính xác. Nếu AI được trình bày với trạng thái trò chơi mà nó không thể thắng hoặc hòa (ví dụ: bẫy kép), thì nó được phép thua. Tuy nhiên, AI không bao giờ nên cho phép trò chơi rơi vào trạng thái thua cuộc từ một bảng trống.
Joe Z.

Tôi có cho rằng chính xác AI luôn là người đầu tiên chơi không?
John Dvorak

1
hmm ... có vẻ như chúng ta được phép vẽ ngay cả khi chúng ta có thể buộc một chiến thắng. Điều đó có đúng không?
John Dvorak

2
Hah Tôi mới tìm hiểu về trò chơi này, và điều đầu tiên khi tôi về nhà là đăng nó ở đây. Than ôi, tôi đã bị đánh bại nó.
gian hàng

Câu trả lời:


6

GolfScript ( 129 86 81 85 75 ký tự)

{:C[{.`{1$-\{+15\-}+%}:T+/}/10,1>C~+-:^{.{^T&}+C/,2<*T}/5^{1&}$][]*^&0=}:N;

Định dạng đầu vào dự kiến: [[int int ...][int int ...]]trong đó danh sách đầu tiên là số của tôi và danh sách thứ hai là số của đối thủ. Để thử nghiệm tương tác, thêm ~Nvào cuối tập lệnh và cung cấp một chuỗi theo định dạng đó: vd

$ golfscript.rb 15.gs <<<"[[5][2 8]]"
9
$ golfscript.rb 15.gs <<<"[[2][5 8]]"
6

Heuristic:

  1. Nếu tôi có thể giành chiến thắng trong lượt này, hãy làm điều đó
  2. Nếu đối thủ thắng lượt tiếp theo, hãy chặn
  3. Nếu tôi có thể buộc đối thủ vào một hình vuông ngăn họ tạo ngã ba, hãy làm điều đó
  4. 5 là con số duy nhất có thể góp phần chiến thắng theo 4 cách, vì vậy hãy nắm lấy nó nếu có.
  5. Ưu đãi phát triển hơn tỷ lệ cược

Khung kiểm tra:

{:Set;[1 5 9 1 6 8 2 4 9 2 5 8 2 6 7 3 4 8 3 5 7 4 5 6]3/{.Set&=},!!}:isWin;
{
    # Mine His
    .isWin{
        "Lost "@`@`++puts
    }{
        # If there are available moves, it's my move.
        # If I won before my move, I've still won after it.
        1$1$+,9<!!{
            # my move
            1$1$[\\]N 2$\+
            # Mine His Mine'
            .isWin!{
                # his move
                10,1>2$2$+-{
                    2$\+1$\
                    # Mine His Mine' Mine' His'
                    fullTest
                    # Mine His Mine'
                }/
            }*;
        }*;;
    }if
}:fullTest;
# I move first
'[][]fullTest'puts [][]fullTest
# He moves first
'[][1]fullTest'puts [][1]fullTest
'[][2]fullTest'puts [][2]fullTest
'[][5]fullTest'puts [][5]fullTest

Bạn có thể chạy đầu vào này cho tôi không: [5][3](nên trả về 4 hoặc 8).
Joe Z.

9- nhưng sau đó bạn dường như đã thay đổi các quy tắc.
Peter Taylor

Ngoài ra, tại sao chỉ 4hoặc 8?
Peter Taylor

Oh chờ đợi, đừng bận tâm, tôi đã sai. Bất cứ điều gì ngoại trừ 7nên làm việc, vì vậy 9được chấp nhận.
Joe Z.

Ngoài ra, tôi không có ý thay đổi các quy tắc; chỉ là tôi đã nói sai họ lần đầu tiên.
Joe Z.

4

Ruby, 330 315 341 ký tự

def m i
$_=i.join
l='159258357456168249267348'.scan /(.)(.)(.)/
return 1 if /^5(28|46|64|82)$/
return 4 if /^[258]{3}$/
return 2 if /^[456]{3}$/
i.each{|i|l.map{|l|return l if(l-=i).size==1&&!/[#{l=l[0]}]/}}
.map{|i|l.map{|m|l.map{|l|return (l&m)[0] if(z=l-i|m-i).size==3&&l!=m&&!/[#{z.join}]/}}}
"524681379".chars{|z|return z if !/#{z}/}
end

Bây giờ tôi sẽ giữ lại các chi tiết, nhưng hãy nói rằng nó dựa trên thuật toán tối ưu cho một vấn đề tương tự đã được giải quyết và thuật toán tối ưu của chúng đã hoạt động tốt như ở đây. Giả định đã được thực hiện - điều này sẽ chọn các nước đi xấu trong các tình huống không thể được tạo ra bởi thuật toán này khi chơi với người chơi khác, chỉ bởi hai người chơi với nhau.

Đầu vào: một mảng gồm hai mảng của một chuỗi có một chữ số. Mỗi mảng đại diện cho các giá trị được lấy bởi một người chơi - người đầu tiên là AI, người thứ hai là đối thủ.

Đầu ra: một số hoặc một chuỗi một chữ số. Chúng tương đương về mặt ngữ nghĩa. Chuẩn hóa thành chuỗi sẽ có giá 8 ký tự.

Có thể lưu thêm ba ký tự nếu chúng ta giả sử thứ tự các số do người gọi đưa ra - thay đổi regex trong L5 thành /^285$/hoặc /^258$/tùy theo thứ tự được tạo từ trò chơi (opponent)5-(ai)2-(opponent)8.


Có vẻ như bạn có một khoản tiết kiệm dễ dàng trong ba dòng cuối cùng bằng cách di chuyển 5đến điểm bắt đầu của thứ tự ưu tiên của bạn.
Peter Taylor

@ah, vâng, cảm ơn Tôi đã có một bước khác ở giữa mà tôi đã loại bỏ (đặc biệt lên trên cùng) và tôi quên không hợp nhất các bước xung quanh. Tôi sẽ chỉnh sửa khi tôi về nhà (trừ khi bạn tình nguyện trước đó).
John Dvorak

1

GolfScript ( 90 85 84 ký tự)

{.~.,3/*..2%.@^++3*3/{~++15=},,*10,1>2$~+-@`{([2$+]+v[0=~)\]}+%[1,]or$0=+}:v{1=}+:N;

Điều này có một cách tiếp cận hoàn toàn khác, nhưng có khả năng dễ bị tối ưu hóa để đánh bại phương pháp heuristic. Ở đây chúng tôi làm một phân tích cây trò chơi đầy đủ, vô cùng chậm. (Không, ý tôi là vậy. Phải mất vài giờ để chạy thử nghiệm đầy đủ, chủ yếu là do việc `{...}+thêm trạng thái hiện tại vào vòng lặp di chuyển tiếp theo). Lưu ý rằng phần cứng đang xác định trạng thái chiến thắng (một phần ba mã, hiện tại).

Có một số hack xấu xí trong các phần không đệ quy. Cụ thể, khi vị trí được xác định là mất một vị trí, chúng tôi lấy vị trí của mình làm [value move]mảng, dựa vào di chuyển là không liên quan và giá trị là khác không.

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.