Ở mỗi nước đi tác tử máy luôn chọn nước đi tốt nhất có thể đó là ăn được nhiều quân của đối phương nhất và để các nước đi tiếp theo đối phương ăn được ít quân nhất của nó nhất.. Khi bàn
Trang 1TRƯỜNG ĐẠI HỌC ĐIỆN LỰC
KHOA CÔNG NGHỆ THÔNG TIN
BÁO CÁO CHUYÊN ĐỀ HỌC PHẦN TRÍ TUỆ NHÂN TẠO
ĐỀ TÀI:
XÂY DỰNG PHẦN MỀM CHƠI CỜ
HEXXAGON
Sinh viên thực hiện : DƯƠNG PHƯƠNG NAM
LÊ BẬT ĐẠT NGUYỄN ĐỨC THẮNG
Giảng viên hướng dẫn : VŨ VĂN ĐỊNH
: CÔNG NGHỆ THÔNG TIN Ngành
Chuyên ngành : CÔNG NGHỆ PHẦN MỀM
Hà Nội, tháng 9 năm 2023
Trang 2PHIẾU CHẤM ĐIỂM
ST
T
Họ và tên sinh viên Nội dung thực hiện Điểm Chữ ký
1 Dương Phương Nam Phân tích thiết kế hệ thống
quản lý quán bán cafe và sách
2 Lê Bật Đạt Phân tích thiết kế hệ thống
quản lý quán bán cafe và sách
Giảng viên chấm 1:
Giảng viên chấm 2:
Nguyễn Đức Thắng
Trang 3- 2 -
MỤC LỤC
CHƯƠNG I GIỚI THIỆU VÀ MÔ TẢ BÀI TOÁN 4
I Đề tài 4
II Mô tả bài toán 4
CHƯƠNG II PHƯƠNG PHÁP GIẢI QUYẾT BÀI TOÁN 6
I Game tree (cây biểu diễn trò chơi) 6
II Thuật toán Minimax 7
III Thuật toán AlphabetaPrunning 7
CHƯƠNG III CHỨC NĂNG VÀ CÁCH SỬ DỤNG HỆ THỐNG 11
CHƯƠNG IV CÁC VẤN ĐỀ GẶP PHẢI VÀ HƯỚNG GIẢI QUYẾT 15
I Giao diện chương trình 15
II Thuật toán AI 15
III Một số lỗi phát sinh khi chạy chương trình 16
IV Hướng phát triển của bài toán 16
CHƯƠNG V KẾT QUẢ 17
CHƯƠNG VI CÔNG NGHỆ VÀ THUẬT TOÁN SỬ DỤNG 18
I Ngôn ngữ lập trình Java 18
II Lập trình hướng đối tượng trong Java 18
III Game engine JGame 19
Tài liệu tham khảo
20
Trang 4CHƯƠNG I GIỚI THỆU VÀ MÔ TẢ BÀI TOÁN
I ĐỀ TÀI
Xây dựng phần mềm chơi cờ Hexxagon
Về cờ Hexxagon
Hexxagon là một biến thể của Ataxx, được chơi trên bàn cờ hình lục giác thay vì hình vuông của Ataxx Bản chính thức được viết bởi Argo Games vào năm 1992 Năm 1993 nó được phát hành dưới dạng PC Game bởi công ty Software Creations, luật chơi vẫn được giữ như của Ataxx Hiện nay nó được phát triển và cập nhật trên web bởi Neave
http://www.neave.com/games/hexxagon/
II MÔ TẢ BÀI TOÁN
1 Mục đích:
Tạo ra một trò chơi đối kháng giữa hai đối thủ máy tính và con người
2 Yêu cầu:
Đưa ra thuật toán giúp giải quyết bài toán đặt ra: Sao cho khả năng để máy tính thắng là lớn nhất
Hoàn thiện chương trình, đồng thời tối ưu hoá thuật toán đưa ra sao cho chương trình làm việc hiệu quả
Khắc phục lỗi phát sinh trong quá trình giải quyết bài toán
3 Cách thức chơi:
Ban đầu mỗi bên có 3 quân khác màu được bố trí xen kẽ tại sáu đỉnh của bàn cờ hình lục giác
Máy sẽ được đi nước đầu tiên, sau đó thay phiên nhau đi các nước
Trang 5Ở mỗi lần đi nếu di chuyển trong 1 ô quân đó sẽ được nhân đôi, nếu di chuyển 2 ô quân đó sẽ thực hiện nhảy mà ko nhân đôi
Sau khi đi tất cả quân của đối phương bên cạnh mà cách 1 ô sẽ biến thành quân cùng màu với nó
Ở mỗi nước đi tác tử máy luôn chọn nước đi tốt nhất có thể đó là ăn được nhiều quân của đối phương nhất và để các nước đi tiếp theo đối phương ăn được ít quân nhất của nó nhất
Khi bàn cờ đầy bên nào có nhiều quân trên bàn cờ hơn thì thắng hoặc khi một bên nào đó không còn nước đi thì các ô trống còn lại trên bàn cờ sẽ thuộc về đối phương, trò chơi kết thúc và so sánh số quân hai bên để tìm người thắng
- 6 -
Trang 6CHƯƠNG II PHƯƠNG PHÁP GIẢI QUYẾT BÀI TOÁN
Đây là một chò trơi đối kháng hai tác tử, thuật giải hiều quả để giải quyết bài toán là các thuật giải tìm kiếm thông minh Minimax/Maximin Với yêu cầu
là một PC game nên thuật toán cần phải có thời gian thực hiện trong khoảng thời gian chấp nhận được đối với gamer, nhưng với bàn cờ này khi độ sâu của cây tìm kiếm là 5 thì số lượng nút cần xét có thể lên đến 3-4 triệu nút, thời gian chạy của máy tính có thể lên đến hàng phút Vậy nên để được kết quả hiệu quả hơn thì cài đặt thuật toán cải tiến AlphaBetaPrunning là điều bắt buộc
Chi tiết về phương pháp:
I GAME TREE (CÂY BIỂU DIỄN TRÒ CHƠI)
Xem xét vấn đề thực hiện một chương trình máy tính để chơi một trò chơi
Để đơn giản hoá, chúng ta chỉ xem xét trò chơi với hai thuộc tính sau:
Trò chơi đối kháng với hai người chơi
Chỉ có một người thắng duy nhất, còn người chơi còn lại là người thua, không có bất cứ sự hợp tác nào giữa hai người chơi
Các loại trò chơi này thường có các bàn cờ cổ điển, như cờ caro (tic tac toe), cờ vua (chess), cờ tướng (checkers),… Với loại trò chơi này, chúng ta có thể mô hình hoá chúng bằng cách sử dụng cây biểu diễn trò chơi (game tree)
Trang 7Trên đây là một phần cây biểu diễn trò chơi của trò cờ caro (tic tac toe) Mỗi nút đại diện cho một trạng thái của bàn cờ và các con của mỗi nút là các trạng thái hợp lệ khi thực hiện nước đi tiếp theo Để điểm từng trạng thái, chúng
ta sẽ gán cho mỗi trạng thái là thuận lợi với người chơi thứ nhất một số dương (càng dương thì càng thuận lợi) Tương tự, chúng ta sẽ gán cho mỗi trạng thái đó
là thuận lợi đối với người chơi thứ hai một số âm (càng âm thì càng thuận lợi) Trong thí dụ này, người chơi thứ nhất đánh dấu “X”, còn người chơi thứ hai đánh dấu “O”, và chỉ với ba điểm (-1, 0, +1), chúng ta sẽ có +1 cho chiến thắng của “X”, -1 cho chiến thắng của “O”, và 0 nếu không ai thắng (hoà) Lưu ý ở đây, các điểm màu xanh chỉ có thể được gán cho trạng thái hiện tại Để tính điểm cho các vị trí khác, chúng ta phải quan sát các trạng thái nút con của nó, và chúng ta sẽ sử dụng thuật toán dưới đây:
II THUẬT TOÁN MINIMAX
Bây giờ, chúng ta có một cách để diễn tả trò chơi trong chương trình của chúng ta, làm thế nào để có thể tính toán được nước đi tối ưu? Giả định rằng đối thủ luôn có thể tính toán được nước đi như chúng ta, và đối thủ sẽ luôn chọn nước đi tối ưu nhất (Tương phản với điều này, ví dụ như, người chơi đầu tiên sẽ tạo ra một cái bẫy với hy vọng rằng đối thủ sẽ mắc bẫy và giành được chiến thắng một cách nhanh chóng Tuy nhiên, nếu đối thủ không mắc bẫy, người chơi này sẽ nhận thấy rằng vị trí của mình hiện đang bị giảm sút)
Một thuật toán để tính toán nước đi tốt nhất là thuật toán Minimax:
minimax(player, board) if(game over in current board position) return winner children = all legal moves for player from this board if(max's turn) return maximal score of calling
minimax on all the children else (min's turn) return
minimal score of calling minimax on all the children
Thuật toán này sẽ diễn ra trong bao lâu? Với các trò chơi phức tạp như Cờ vua hay Cờ vây thì để tìm kiếm lời giải đến khi kết thúc trò chơi sẽ phải trả một giá rất đắt về thời gian Trên thực tế, nếu làm như vậy đối với Cờ vua, trong thời gian để phân tích một nước đi đó có lẽ mặt trời và trái đất cũng không còn tồn tại Tuy nhiên, có một cách tối ưu hoá để cho thuật toán đơn giản ở trên tiết kiệm rất nhiều việc tìm kiếm và cho phép chúng ta tăng tối đa độ sâu tìm kiếm Thuật toán tối ưu hoá đựa trên Minimax đó là AlphaBetaPrunning
- 8 -
Trang 8III THUẬT TOÁN AlphaBetaPrunning
Với các trò chơi cờ đối kháng như trên, ý tưởng về cơ bản được thể hiện như sau: giả sử đến lượt chúng ta đi nước cờ của mình và chúng ta tính được nước đi
A cho chúng ta một lợi thế lớn Bây giờ chúng ta tính đến một nước đi B và thấy rằng nước đi đáp trả đầu tiên của đối thủ chúng ta đoán trước đối thủ có thể ép chúng ta về thế hoà! Vậy thì chúng ta cần gì phải xét đến nước đi B này nữa, bởi
ở thời điểm này ta biết rằng nếu ta đi nước B thì kết quả tốt nhất mà ta đạt được chỉ là một nước đi hoà cho cả hai và chúng ta lại đã biết nước đi A sẽ cho ta lợi thế hơn nếu chúng ta đi nước đó
Để hình thức hoá ý tưởng, chúng ta sẽ theo dõi hai con số, alpha và beta cho mỗi nước đi mà chúng ta phân tích Alpha sẽ là giá trị của nước đi tốt nhất có thể
mà chúng ta đi được chúng ta tính toán xa nhất có thể (tức là số nước đi của hai bên xa nhất mà ta tính được) Beta là giá trị của nước đi tốt nhất có thể của đối thủ mà chúng ta tính được xa nhất có thể Nếu một lúc nào đó alpha >= beta thì nước đi tốt nhất của đối thủ có thể ép chúng ta vào thế tồi hơn là nước đi tốt nhất của chúng ta lúc đó, do đó ta không cần phải phân tích xa hơn nước đi đó nữa Điều kiện cắt tỉa cũng được áp dụng tương tự nếu chúng ta là người chơi ở vị trí min, nhưng thay vì tìm nước đi lợi cho alpha thì ta tìm nước đi lợi cho beta Sau đây là thuật toán thực hiện alpha beta cắt tỉa
( http://www.ocf.berkeley.edu/~yosenl/extras/alphabeta/alphabeta.html )
//AlphaBetaPrunning Algorithm
alpha-beta(player, board, alpha, beta) if(game over in
current board position) return winner children = all
legal moves for player from this board if(max's turn)
for each child score = alpha-beta(other
player,child,alpha,beta) if score > alpha then alpha
= score (we have found a
better best move)
if alpha >= beta then return alpha (cut off)
return alpha (this is our best move) else (min's turn)
for each child score = alpha-beta(other
player,child,alpha,beta) if score < beta then beta =
score (opponent has found
a better worse move)
if alpha >= beta then return beta (cut off)
return beta (this is the opponent's best move)
Dựa trên thuật toán này nhóm em đã thực hiện thuật toán trên bàn cờ của mình như sau:
Trang 9- 10 -
Trang 10Hàm alphaBetaPrunning trả về 1 giá trị là số nguyên, có 5 tham số đầu vào:
currentBoard: Trạng thái hiện tại của bàn cờ
Độ sâu tìm kiếm: (int depth) được chọn = 3
Giá trị alpha: (int alpha) giá trị của nước đi tốt nhất đối với máy
Giá trị beta: (int beta) giá trị của nước đi tốt nhất đối với người
Boolean returnBestMove: dùng để chặn không cho các lần gọi
alphabetaPrunning ghi đè giá trị bestMove, nên ở lần gọi đầu tiên giá trị của nó là true nhưng trong các lần gọi đệ quy, giá trị của nó là false Với trạng thái bàn cờ hiện tại copy ra 1 bàn cờ khác, lấy ra 1 mảng bao gồm tất cả các nước đi hợp lệ đối với người chơi hiện tại, với từng nước đi thực hiện di chuyển nó trên bàn cờ copy, cập nhật trạng thái mới của bàn cờ, đánh giá giá trị của bàn cờ mới bằng cách gọi hàm
alphaBetaPrunning với độ sâu giảm đi 1
Nếu là nước đi của máy, nó sẽ luôn chọn giá trị ứng với
alphaBetaPrunning là lớn nhất, ngược lại người sẽ chọn ứng với giá
trị nhỏ nhất
Kiểm tra nếu alpha >= beta thì nhánh tìm kiếm đó được cắt đi
Hàm đánh giá trạng thái bàn cờ (int evaluate(board)) trả lại giá trị của bàn cờ đối với một người chơi (người hoặc máy):
Số quân của máy * Số quân của máy - Số quân của người * Số quân của người
Trang 11CHƯƠNG III CHỨC NĂNG VÀ CÁCH SỬ DỤNG HỆ
THỐNG
Cài đặt và chạy chương trình
Yêu cầu: Máy tính cài đặt sẵn J2SE 1.4 trở lên
Chạy trực tiếp bằng file Hexxagon.jar trong thư mục
AIHexxagon\Hexxagon\src\dist
Game hexxagon có giao diện khá đơn giản
Bàn cờ gồm các ô cờ màu tím
Mỗi một ô cờ là một hình lục giác (hexagon) Hai góc
trên thể hiện số quân cờ đang có của mỗi bên
Góc dưới bên trái thể hiện việc trỏ chuột của người chơi, thông báo đến lượt đi của người chơi hay của máy tính
Góc phía dưới bên phải của màn hình có hiển thị thông tin (chủ yếu dùng cho việc debug việc click tìm vị trí quân cờ) Toạ độ con trỏ (screen)
Vị trí của con trỏ trên bàn cờ (index)
Thời gian (timer)
Để vào chơi ta nhấn phím cách (space)
- 12 -
Trang 12Khi bắt đầu trò chơi
Mỗi bên (máy – người) sẽ có ba quân cờ được bố trí sole đối xứng như hình dưới
Máy có quân cờ màu caro trắng-đỏ
Người có quân cờ màu xanh
Trên cùng bên trái hiển thị số quân cờ của người chơi (You)
Trên cùng bên phải hiển thị số quân cờ của máy (Com)
Máy được đi trước (do yêu cầu chơi với chương trình chơi cờ khác)
Cách chơi
Trang 13Để đi quân cờ nào ta kích chuột vào quân cờ đó, khi đó trên bàn cờ sẽ hiển thị các ô cờ có viền (được phép đi):
Viền màu xanh: Nếu đi vào các ô cờ có viền màu xanh thì quân cờ
sẽ được nhân đôi, tức ngoài quân cờ ở vị trí ô cờ cũ, ta được thêm một quân cờ ở vị trí ô cờ mới đi (Số lượng các quân cờ của ta tăng thêm 1)
Viền màu vàng: Nếu đi vào các ô cờ có viền màu vàng thì quân cờ
sẽ được di chuyển tới ô cờ đó (số lượng các quân cờ của ta vẫn được giữ nguyên)
Với mỗi nước đi, tất cả các quân cờ của đối phương nằm ngay cạnh nước
đi đó sẽ bị “ăn”, tức sẽ chuyển màu và biến thành quân cờ của mình
Game over!
Lượt đi của người và máy xen kẽ nhau, cứ thế ta đi hết bàn cờ
- 14 -
Trang 14Khi các ô cờ đã kín hoặc một bên không thể đi nữa do đã bị đối phương vây kín thì trò chơi kết thúc Khi đó bên nào có số quân cờ chiếm đa số (nhiều hơn đối phương) thì giành chiến thắng
Vì giải thuật có độ sâu tìm kiếm lớn nên bạn rất khó có thể thắng được máy Và đây là kết cục…
Trang 15
CHƯƠNG IV CÁC VẤN ĐỀ GẶP PHẢI VÀ HƯỚNG
GIẢI QUYẾT
I GIAO DIỆN CHƯƠNG TRÌNH
Khó khăn: Vì chưa có kinh nghiệm lập trình trò chơi do đó lúc đầu nhóm
em chưa tìm ra được hướng giải quyết tốt nhất cho việc thiết kế giao diện: lựa chọn giữa dùng thư viện có sẵn của Java là JGame cho trò chơi 2D hay chọn 1 thư viện khác như LWJGL có hỗ trợ OpenAL và OpenGL để
có thể dễ dàng thiết kế giao diện trò chơi…
Hướng giải quyết: Nếu sử dụng các thư viện có hỗ trợ openGL thì việc
tìm hiểu và viết code sẽ mất rất nhiều thời gian Sau khi cùng nhau tìm hiểu nhóm em đã thấy được rằng thư viện JGame của Java có rất nhiều tiện ích đủ để tạo ra được 1 giao diện tốt và cũng không quá phức tạp
- 16 -
Trang 16trong lập trình Việc làm chủ được Jgame chỉ mất 4-5 ngày làm việc liên tục, từ đọc tutorial đến document của Jgame
II THUẬT TOÁN AI
Khó khăn:
1. Thuật toán AI được coi là phần quan trọng nhất của đồ án, tuy nhiên
vì mới được làm quen với thuật toán này, do đó lúc đầu khi tìm hiểu để lập trình với một thuật toán đơn giản và dễ hiểu nhóm đã gặp nhiều khó
khăn
2. Vấn đề bộ nhớ khi cây tìm kiếm quá sâu, lúc đầu cả nhóm đã không
sử dụng độ sâu giới hạn nên vừa chạy chương trình đã gây lỗi StackOverflow
3. Các phương thức move hay getAllvalidMoves hoạt động không chính xác gây ra kết quả hiển thị cũng như kết quả của các nước đi không chính xác Có khi quân của máy tính ăn được quân của người chơi nhưng trên bàn cờ cũng như trong bộ nhớ lưu trữ bàn cờ không thể hiện điều này
4. Phương thức evaluate hoạt động không được hiệu quả khi đánh giá bàn cờ đối với mỗi nước đi của người chơi nên thỉnh thoảng còn có những nước đi bằng mắt thường có thể nhận xét là chưa được tốt (thấy rõ khi để depth = 4 và cho hai bên đều là máy chơi cờ với nhau)
Hướng giải quyết:
1 Sau khi đọc được thuật toán trình bày khá trong sáng và dễ hiểu tại
http://www.ocf.berkeley.edu/~yosenl/extras/alphabeta/alphabeta.html chúng em
đã quyết định dùng thuật toán này để cài đặt cho chương trình của mình
2 Bạn Giang đã đề xuất việc dùng độ sâu giới hạn, mỗi lần gọi đệ quy
tiếp theo độ sau giảm đi 1, đến khi độ sâu của cây tìm kiếm bằng 0 thì thuật toán trả về giá trị của bàn cờ đối với người chơi tương ứng
3 Do đã sử dụng sai tham chiếu đối tượng trong Java nên có khi đến nước
đi của máy thì hàm move lại thực hiện một nước đi trên bàn cờ được copy ra khi thực hiện thuật toán alphabetaPrunning do con trỏ lưu trong bestMove trỏ đến các quân cờ trong các bàn cờ copy này Nhóm
đã bàn bạc và đưa ra phương án: sử dụng vị trí được lưu sẵn trong từng quân cờ chứ không sử dụng con trỏ đến các quân cờ đó khi thực hiện phương thức move, lỗi này đã được khắc phục hoàn toàn
4 Ban đầu nhóm sử dụng hàm evaluate có giá trị trả về là:
số quân của máy * 10 - số quân của người