Người thắng là người đầu tiên có được mộtchuỗi liên tục gồm 4 quân hàng ngang, hoặc dọc, hoặc chéo không bị chặn đầu nào.Một khi đã đặt xuống, các quân cờ không thể di chuyển hoặc bỏ ra
CƠ SỞ LÝ THUYẾT
Đặt vấn đề
Yêu cầu bài toán : Xây dựng một bàn cờ có kẻ các ô vuông với kích thước 20x20 Có 2 quân cờ là X và O Người chơi có thể đánh với máy hoặc 2 người chơi với nhau Người thắng là người đi được 5 quân cờ cùng kiểu trên hang dọc, hàng ngang hoặc đường chéo Hai người hoà nhau khi bàn cờ hết chỗ đánh mà vẫn chưa phân được thắng bại.
Chương trình có các chức năng:
- Undo: Hoàn tác lại nước đi nước vừa đánh - Redo: Trả lại nước đi vừa hoàn tác
- PlayerVsCom: Chức năng đánh cờ với máy - PlayerVsPlayer: Chức năng đánh cờ với người chơi - Thoát: Thoát khỏi trò chơi
Các lớp của chương trình (class):
- Lớp CaroChess: Chứa các hàm chức năng của trò chơi - Lớp BanCo: Khai báo các biến, vào khởi tạo bàn cờ, quân cờ - Lớp Oco: Khai báo các biến, vào khởi tạo ô cờ
- Lớp Form1: Chứa form và các xử lý sự kiện- Lớp Program: Chạy chương trình
Trò chơi bắt đầu bằng việc chọn chế độ Sau đó chương trình sẽ khởi tạo bàn cờ với kích thước 20x20 ô (mỗi ô ban đầu đều trống) Chúng ta sử dụng vòng lặp chơi game, vòng này sẽ lặp liện tục đến khi có người chiến thắng Trong trò chơi cờ caro này, người chơi sẽ chọn vị trí A muốn đặt quân cờ bằng click chuột, sau đó hệ thống sẽ kiểm tra vị trí đã chọn có hợp lệ hay không (tức là vị trí đó còn trống) Nếu không hợp lệ (hay bị trùng lên quân cơ khác) thì yêu cầu người chơi chọn lại vị trí (quay lại bước chọn vị trí) Nếu hợp lệ thì người chơi tiếp theo chọn vị trí quân cờ của mình Sau khi đã hoàn thành phần chọn vị trí, hệ thống sẽ cập nhật bàn cờ bằng cách đặt quân cờ của người chơi vào vị trí đã chọn trên bàn cờ Khi trò chơi tiếp tục, hệ thống sẽ kiểm tra người thắng bằng cách kiểm tra xem sau nước đi vừa rồi, người chơi hiện tại có thắng hay không (kiểm tra 4 hướng : ngang, dọc, chéo chính, chéo ngược) Nếu có người chiến thắng, in thông báo người thắng và kết thức trò chơi.
Nếu không có người chiến thắng, hệ thống sẽ kiểm tra xem còn ô trống trên bàn cơ khay không Nếu không còn ô trống, in thông báo hòa cờ Nếu còn ô trống, chuyển lượt cho người chơi tiếp theo (từ X sang O hoặc ngược lại) Quá trình này lặp lại cho đến khi trò chơi kết thúc.
Tổng quan về giao diện người dùng trò chơi Cờ Caro
2.2.1 Các khái niệm cơ bản trong lập trình game cờ caro 2.2.1.1 Bàn cờ (Board)
Bàn cờ là một ma trận các ô vuông (cell), mỗi ô có thể chứa một ký hiệu X, O hoặc để trống Bàn cờ có thể có nhiều kích thước khác nhau, nhưng phổ biến nhất là 3x3, 5x5, hoặc lớn hơn tùy theo yêu cầu của người chơi.
Mỗi ô cờ là một thành phần của bàn cờ, và có thể ở trạng thái trống, chứa ký hiệu cờ xanh hoặc cờ đỏ.
Trò chơi có hai người chơi, thường được ký hiệu là Player cờ xanh và Player cờ đỏ Hai người chơi sẽ lần lượt đánh dấu vào các ô trên bàn cờ.
Người chơi cờ xanh đi trước, sau đó đến người chơi cờ đỏ.Mỗi lượt đi, người chơi sẽ đánh dấu cờ xanh hoặc cờ đỏ vào một ô trống trên bàn cờ.Người chiến thắng là người đầu tiên có một dãy 5 ô liên tục có các ký hiệu của mình theo hàng ngang, hàng dọc hoặc đường chéo.Trò chơi kết thúc khi một trong hai người chơi thắng hoặc không còn ô trống nào để đi (hòa).
2.2.2 Thiết kế giao diện người dùng (UI)
Khung chơi game sẽ bao gồm một lưới các ô (Cell) có thể đặt click để đặt quân cờ trên bàn cờ Bàn cờ được tạo từ Panel để tạo lưới bàn cờ, trong đó có sự kiện Click để người chơi đặt quân cờ.
Button chế độ chơi (PlayerVsPlayer ; PlayerVsCom) được đặt phía dưới Label.
Người chơi cần click chuột vào các nút này để chọn chế độ chơi Ngoài ra, còn button Thoát được tạo ra để người chơi click chuột vào khi muốn ngừng chơi.
Lable được sử dụng để hiện thông tin Ở đây, lable hiện thông tin luật chơi để người chơi có thể hiểu được cách chơi đúng nhất của game.
Thanh Menu giúp tổ chức các chức năng của ứng dụng một cách hệ thống, giúp người dùng dễ dàng tìm kiếm và sử dụng các chức năng này Vì vậy trong game cờ caro, thanh Menu có chứa các mục sau :
File: Chứa các tùy chọn để bắt đầu trò chơi (New) và thoát trò chơi (Exit).
Trong tùy chọn New ta có 2 lựa chọn chế độ chơi: PlayerVsPlayer,
PlayerVsCom Người dùng có thể chọn chế độ chơi ở button phía dưới hoặc trong thanh Menu New đều được Điều này tạo cho người chơi một môi trường tiện lợi hơn.
Tổng quan về thuật toán
2.3.1 Khởi tạo bàn cờ 2.3.1.1 Khởi tạo ô cờ:
Tạo ô cờ với chiều cao và chiều rộng bằng 20, với các biến lần lượt là dòng, cột, vị trí ô cờ, sở hữu ô cờ.
2.3.1.2 Thuật toán vẽ bàn cờ:
1 Phương thức VeBanCo nhận đối số Graphics g - đây là đối tượng đồ họa được sử dụng để vẽ lên bề mặt.
2 Trong vòng lặp đầu tiên, chúng ta lặp _SoCot lần (số cột trên bàn cờ) Trong mỗi lần lặp, chúng ta vẽ một đường thẳng ngang từ tọa độ (i * OCo._ChieuRong, 0) đến (i * OCo._ChieuRong, _SoDong * OCo._ChieuCao) Đây là các đường dọc chia bàn cờ thành các cột.
3 Trong vòng lặp thứ hai, chúng ta lặp _SoDong lần (số dòng trên bàn cờ).
Trong mỗi lần lặp, chúng ta vẽ một đường thẳng dọc từ tọa độ (0, j * OCo._ChieuCao) đến (_SoCot * OCo._ChieuRong, j * OCo._ChieuCao) Đây là các đường ngang chia bàn cờ thành các dòng.
4 Kết quả là một lưới các ô vuông tạo thành bàn cờ.
1 Mục đích của phương thức này là khởi tạo một mảng 2 chiều các đối tượng Oco, mỗi ô có tọa độ và trạng thái khởi tạo.
2 Trong vòng lặp bên ngoài, chúng ta lặp qua từng dòng của bàn cờ, từ 0 đến _BanCo.SoDong - 1.
3 Trong mỗi vòng lặp bên trong, chúng ta lặp qua từng cột của bàn cờ, từ 0 đến_BanCo.SoCot - 1.
4 Tại mỗi ô (i, j), chúng ta tạo một đối tượng OCo mới với các thông tin sau: chỉ số dòng: i; chỉ số cột: j; tọa độ của ô: new Point (j * OCo._ChieuRong, i * OCo._ChieuCao); trạng thái khởi tạo: 0 (chưa có quân cờ)
5 Chúng ta lưu đối tượng OCo mới này vào mảng _MangOCo tại vị trí (i, j).
Kết quả tạo được một mảng ô cờ 2 chiều với 20x20 ô ở chế độ khởi tạo
2.3.2 Đánh cờ theo chế độ chơi
1 Kiểm tra xem vị trí con trỏ chuột (MouseX, MouseY) có phù hợp với kích thước của một ô cờ hay không:
2 Nếu MouseX không chia hết cho OCo._ChieuRong (chiều rộng của một ô cờ), trả về false vì vị trí không phù hợp.
3 Tính toán vị trí ô cờ mà con trỏ chuột đang trỏ tới:
Chỉ số cột Cot = MouseX / OCo._ChieuRong
Chỉ số dòng Dong = MouseY / OCo._ChieuCao 4 Kiểm tra xem ô cờ tại vị trí (Dong, Cot) đã có quân cờ hay chưa:
Nếu _MangOCo[Dong, Cot].Sohuu != 0, tức là ô cờ đã có quân cờ, trả về false vì không thể đánh thêm quân cờ.
5 Xử lý việc đánh cờ tùy theo lượt đi hiện tại:
Nếu _LuotDi == 1, đánh quân cờ màu xanh dương (sbBlue) và chuyển lượt đi sang người chơi 2 (_LuotDi = 2).
Nếu _LuotDi == 2, đánh quân cờ màu đỏ (sbRed) và chuyển lượt đi sang người chơi 1 (_LuotDi = 1).
Nếu _LuotDi có giá trị khác 1 hoặc 2, hiển thị thông báo "Có lỗi".
6 Lưu trữ thông tin về nước đi vừa được thực hiện:
Tạo một đối tượng OCo mới với thông tin về ô cờ vừa được đánh.
Đẩy đối tượng OCo này vào stack stk_CacNuocDaDi.
Trả về true để thông báo rằng việc đánh cờ đã thành công.
2.3.3 Nước đi của máy 2.3.3.1 Thuật toán duyệt tấn công:
1 DiemTanCong_DuyetDoc(int currDong, int currCot):
Phương thức này tính điểm tấn công theo chiều dọc của một ô cờ.
Nó duyệt các ô cờ từ vị trí hiện tại (currDong, currCot) về phía dưới và về phía trên để đếm số quân ta và số quân địch.
Nếu có 2 quân địch liên tiếp, phương thức trả về 0 điểm.
Nếu không, phương thức trừ điểm phòng ngự tương ứng với số quân địch và cộng điểm tấn công tương ứng với số quân ta.
2 DiemTanCong_DuyetNgang(int currDong, int currCot):
Phương thức này tính điểm tấn công theo chiều ngang của một ô cờ.
Nó duyệt các ô cờ từ vị trí hiện tại (currDong, currCot) về phía trước và về phía sau để đếm số quân ta và số quân địch.
Nếu có 2 quân địch liên tiếp, phương thức trả về 0 điểm.
Nếu không, phương thức trừ điểm phòng ngự tương ứng với số quân địch và cộng điểm tấn công tương ứng với số quân ta.
3 DiemTanCong_DuyetCheoXuoi(int currDong, int currCot):
Phương thức này tính điểm tấn công theo chiều chéo xuôi của một ô cờ.
Nó duyệt các ô cờ từ vị trí hiện tại (currDong, currCot) về phía trên bên trái và về phía dưới bên phải để đếm số quân ta và số quân địch.
Nếu có 2 quân địch liên tiếp, phương thức trả về 0 điểm.
Nếu không, phương thức trừ điểm phòng ngự tương ứng với số quân địch và cộng điểm tấn công tương ứng với số quân ta.
4 DiemTanCong_DuyetCheoNguoc(int currDong, int currCot):
Phương thức này tính điểm tấn công theo chiều chéo ngược của một ô cờ.
Nó duyệt các ô cờ từ vị trí hiện tại (currDong, currCot) về phía trên bên phải và về phía dưới bên trái để đếm số quân ta và số quân địch.
Nếu có 2 quân địch liên tiếp, phương thức trả về 0 điểm.
Nếu không, phương thức trừ điểm phòng ngự tương ứng với số quân địch và cộng điểm tấn công tương ứng với số quân ta.
2.3.3.2 Thuật toán duyệt phòng ngự:
1 Hàm này duyệt theo chiều dọc (từ trên xuống dưới) từ vị trí hiện tại (currDong, currCot) để tính điểm phòng ngự.
Nó đếm số quân ta và số quân địch trong phạm vi 5 ô liên tiếp dọc.
Nếu số quân ta là 2, không tính điểm Nếu không, nó sẽ cộng điểm dựa trên số quân địch vào biến DiemTong.
Cuối cùng, hàm trả về DiemTong.
2 DiemPhongNgu_DuyetNgang(int currDong, int currCot):
Nó đếm số quân ta và số quân địch trong phạm vi 5 ô liên tiếp ngang.
Nếu số quân ta là 2, không tính điểm Nếu không, nó sẽ cộng điểm dựa trên số quân địch vào biến DiemTong.
Cuối cùng, hàm trả về DiemTong.
3 DiemPhongNgu_DuyetCheoXuoi(int currDong, int currCot):
Nó đếm số quân ta và số quân địch trong phạm vi 5 ô liên tiếp đường chéo xuôi.
Nếu số quân ta là 2, không tính điểm Nếu không, nó sẽ cộng điểm dựa trên số quân địch vào biến DiemTong.
Cuối cùng, hàm trả về DiemTong.
4 DiemPhongNgu_DuyetCheoNguoc(int currDong, int currCot):
Nó đếm số quân ta và số quân địch trong phạm vi 5 ô liên tiếp đường cheo ngược.
Nếu số quân ta là 2, không tính điểm Nếu không, nó sẽ cộng điểm dựa trên số quân địch vào biến DiemTong.
Cuối cùng, hàm trả về DiemTong.
2.3.3.3 Thuật toán tìm kiếm nước đi:
1 Khởi tạo một đối tượng OCo để lưu trữ ô được chọn làm nước đi tốt nhất, và một biến DiemMax để lưu trữ điểm số cao nhất.
2 Lặp qua tất cả các ô trên bàn cờ (mảng _MangOCo):
Kiểm tra xem ô hiện tại có chủ sở hữu hay không (giá trị Sohuu bằng 0 nghĩa là ô trống).
Tính toán điểm số tấn công (DiemTanCong) và điểm số phòng ngự (DiemPhongNgu) cho ô này bằng cách gọi các phương thức trợ giúp
Tính toán điểm số tạm thời (DiemTam) bằng cách lấy giá trị lớn hơn giữa điểm số tấn công và điểm số phòng ngự.
Nếu điểm số tạm thời lớn hơn DiemMax, cập nhật DiemMax và lưu trữ thông tin của ô vào đối tượng oCoResult.
3 Trả về đối tượng oCoResult chứa thông tin về ô được chọn làm nước đi tốt nhất.
1 Phương thức này chịu trách nhiệm đặt một quân cờ lên bàn cờ.
2 Nếu stack stk_CacNuocDaDi rỗng, nó sẽ đặt một quân cờ vào giữa bàn cờ.
3 Nếu stack không rỗng, nó sẽ gọi phương thức TimKiemNuocDi() để tìm nước đi tốt nhất và sau đó đặt quân cờ vào vị trí được tính toán.
2.3.4.1 Thuật toán duyệt các phương:
1 Duyệt theo chiều dọc (DuyetDoc()):
Hàm này kiểm tra xem có liên tiếp 5 quân cờ cùng màu theo chiều dọc hay
Nó sẽ kiểm tra từ vị trí hiện tại trở xuống, nếu tìm thấy 5 quân cờ cùng màu liên tiếp thì trả về true
Nếu vị trí bắt đầu hoặc kết thúc của dãy 5 quân cờ là các ô trống, hàm cũng sẽ trả về true.
2 Duyệt theo chiều ngang (DuyetNgang()):
Hàm này kiểm tra xem có liên tiếp 5 quân cờ cùng màu theo chiều ngang hay không
Nó sẽ kiểm tra từ vị trí hiện tại trở xuống, nếu tìm thấy 5 quân cờ cùng màu liên tiếp thì trả về true
Nếu vị trí bắt đầu hoặc kết thúc của dãy 5 quân cờ là các ô trống, hàm cũng sẽ trả về true.
3 Duyệt theo đường chéo xuôi (DuyetCheoXuoi()):
Hàm này kiểm tra xem có liên tiếp 5 quân cờ cùng màu theo đường chéo xuôi hay không
Nó sẽ kiểm tra từ vị trí hiện tại trở xuống và sang phải, nếu tìm thấy 5 quân cờ cùng màu liên tiếp thì trả về true
Nếu vị trí bắt đầu hoặc kết thúc của dãy 5 quân cờ là các ô trống, hàm cũng sẽ trả về true.
4 Duyệt theo đường chéo ngược (DuyetCheoNguoc()):
Hàm này kiểm tra xem có liên tiếp 5 quân cờ cùng màu theo đường chéo ngược hay không
Nó sẽ kiểm tra từ vị trí hiện tại trở xuống và sang phải, nếu tìm thấy 5 quân cờ cùng màu liên tiếp thì trả về true
Nếu vị trí bắt đầu hoặc kết thúc của dãy 5 quân cờ là các ô trống, hàm cũng sẽ trả về true.
1 Nếu số nước đã đi bằng với số ô trên bàn cờ, trò chơi kết thúc với kết quả hòa.
2 Nếu chế độ chơi là 1 (PlayerVsPlayer), nó sẽ kiểm tra xem có ai thắng bằng cách gọi các hàm DuyetDoc(), DuyetNgang(), DuyetCheoXuoi() và DuyetCheoNguoc() với từng nước đã đi Nếu tìm thấy người chơi thắng, biến _KetThuc được cập nhật tương ứng.
3 Nếu chế độ chơi là 2 (PlayerVsCom), nó sẽ thực hiện tương tự như trường hợp 1, nhưng kết quả thắng sẽ là "Người chơi" hoặc "Máy tính" tùy thuộc vào người chơi nào.
4 Nếu không tìm thấy người thắng, hàm sẽ trả về false.
1 Sử dụng một biến _KetThuc để lưu trạng thái kết thúc trò chơi, có thể là hòa, người chơi 1 thắng, người chơi 2 thắng, người chơi thắng, hoặc máy tính thắng
2 Sau khi hiển thị thông báo, nó đặt biến _SanSang thành false để ngăn người chơi tiếp tục.
Công cụ hỗ trợ
C# (C Sharp) là 1 ngôn ngữ tương đối mới đã được công bố với thế giới khi Microsoft công bố biên bản đầu tiên của họ vào năm 2000 (.NET Framework phiên bản 1.0) Kể từ đó ngôn ngữ này ngày càng phổ biến hơn, và có thể cho rằng nó trở thành ngôn ngữ của sự lựa chọn của Windows và nhà phát triển web sử dụng NET Framework. Đây là ngôn ngữ tương đối đơn giản rất phù hợp với việc học kỹ thuật lập trình cơ bản C# có cú pháp rõ ràng xuất phát từ C/C++ nhưng đơn giản hóa một số các vấn đề trước đây khuyến cáo với các lập trình viên Và cũng là ngôn ngữ có cú pháp đơn giản và dễ hiểu tương tự C/C++ Ngoài ra, C# là 1 trong những ngôn ngữ má chúng ta có thể sử dụng để tạo ứng dụng sẽ chạy trong NET CLR Đó là 1 sự kế trên nền tảng NET C# có thể được sử dụng để phát triển nhiều loại ứng dụng khác nhau như ứng dụng desktop, web, ứng dụng di động và game Ngôn ngữ này còn được thiết kế để hoạt động tối ưu với NET framework, việc đó giúp cung cấp 1 loạt các thư viện và công cụ hỗ trợ mạnh mẽ cho việc phát triển các phần mềm C# là 1 loại an toàn ngôn ngữ (không giống với C++) một khi một số dữ liệu đã được gán cho 1 kiểu thì nó không thể chuyển đổi thành một kiểu khác không liên quan Ngoài ra, C# còn cung cấp các tính năng như quản lý bộ nhớ tự động (garbage collection), kiểm tra kiểu thời gian buên dịch và thời gian chạy, nhờ vào đó mà giúp giảm thiểu lỗi và tăng cường bảo mật
Vậy tại sao lại chọn ngôn ngữ C# cho dự án game cờ caro này ? Cũng vì những ưu điểm trên là lợi thế cho việc xây dựng game cờ caro đơn giản hơn Thứ nhất, việc ngôn ngữ C# có cú pháp rõ rảng, đơn giản, dễ hiểu sẽ giúp cho việc lập trình dễ nắm bắt và triển khai dự án.Thứ hai, C# cùng với sự hỗ trợ của Visual Studio giúp cho việc phát triển, gỡ lỗi cũng như triển khai trò chơi trở nên đơn giản và hiệu quả.Cuối cùng, NET framework kết hợp với C# cung cấp hiệu suất tối đa và độ ổn định cao đảm bảo cho trò chơi có thể hoạt động mượt mà Vì vậy trong đồ án này, chúng em đã tận dụng nhựng ưu điểm của ngôn ngữ để tạo ra sản phẩm hoàn chỉnh nhất có thể.
Window Form là một phần của NET Framework, cung cấp một nền tảng mạnh mẽ để phát triển các ứng dụng desktop với giao diện đồ họa người dùng (UI) trong môi trường Windows.Sử dụng Window Form người lập trình có thể dễ dàng thiết kế và quản lý giao diện của ứng dụng, từ đó giúp tập trung vào logic xử lý và chức năng của các phần mềm.Window Form cũng là 1 thư viện các điều khiển (nút bấm, thanh công cụ, menu, ) mà người dùng có thể sử dụng.
Việc chọn Window Form làm công cụ phát triển giúp mang lại nhiều lợi ích trong thời gian làm đồ án.Window Form có tích hợp chặt chẽ với Visual Studio,cung cấp nhiều công cụ hỗ trợ lập trình, debug và đặc biệt là thiết kế được giao diện Ngoài ra, các control trong Window From có thể tùy biến theo nhu cầu của trò chơi, từ đó tạo ra 1 giao diện người dùng trực quan và sinh động hơn Công cụ Window From này còn hỗ trợ quản lý sự kiện giúp dễ dàng xử lý các tương tác của người chơi như click chuột, di chuyển chuột và nhập liệu từ bàn phím Đây chính là những gì cần trong đồ án lần này, nhờ những tính năng của Window From mà việc phát triển trò chơi cờ caro trở nên thuận lợi và nhanh chóng hơn.
Trong đồ án game cờ caro bằng C#, Window Form được chúng em sử dụng để thiết kế giao diện bàn cờ , các ô cờ trong trò chơi được tạo bằng panel, ngoài ra còn các button cho phép người chơi tương tác bằng cách click chuột Ngoài ra, WindowForm giúp tạo các menu, hộp thoại và các thành phần giao diện khác giúp người chơi dễ dàng thành lập và điều chỉnh trò chơi theo ý muốn của mình Ta còn sử dụng label, textbox để hiển thị các thông tin như điểm số, thời gian, luật chơi , Window Form hỗ trợ về việc xử lý logic của trò chơi bao gồm việc kiểm tra chiến thắng, quản lý lượt chơi và thông báo kết quả Như vậy ta có thể thấy đượcWindows Form là một lựa chọn lý tưởng cho việc phát triển các ứng dụng desktop,đặc biệt là những ứng dụng đòi hỏi giao diện người dùng phức tạp và tương tác cao.
PHÂN TÍCH THUẬT TOÁN
Giao diện khởi tạo
3.1.1 Vẽ bàn cờ 3.1.1.1 Sơ đồ thuật toán
- Hàm vẽ bàn cờ: function VeBanCo(g: Graphics) begin for i = 0 to _SoCot do begin g.DrawLine(CaroChess.pen, i * OCo._ChieuRong, 0, i * OCo._ChieuRong, _SoDong * OCo._ChieuCao) end for j = 0 to _SoDong do begin g.DrawLine(CaroChess.pen, 0, j * OCo._ChieuCao, _SoCot * OCo._ChieuRong, j * OCo._ChieuCao) end end
Vòng lặp đầu tiên dùng để vẽ các đường ngang của bàn cờ Nó lặp từ 0 đến _SoCot (số cột của bàn cờ), vẽ một đường ngang tại mỗi vị trí i *
OCo._ChieuRong (chiều rộng của mỗi ô cờ) từ 0 đến _SoDong * OCo._ChieuCao (chiều cao của bàn cờ).
Vòng lặp thứ hai dùng để vẽ các đường dọc của bàn cờ Nó lặp từ 0 đến _SoDong (số dòng của bàn cờ), vẽ một đường dọc tại mỗi vị trí j * OCo._ChieuCao (chiều cao của mỗi ô cờ) từ 0 đến _SoCot * OCo._ChieuRong (chiều rộng của bàn cờ).
Lưu ý rằng trong code C#, vòng lặp đầu tiên lặp từ 0 đến _SoCot, còn vòng lặp thứ hai lặp từ 0 đến _SoDong Trong mã giả, cả hai vòng lặp đều lặp từ 0 đến giá trị tương ứng.
- Hàm khởi tạo mảng ô cờ: procedure KhoiTaoMangOCo() begin for i = 0 to _BanCo.SoDong - 1 do begin for j = 0 to _BanCo.SoCot - 1 do begin
_MangOCo[i, j] = new OCo(i, j, new Point(j * OCo._ChieuRong, i * OCo._ChieuCao), 0) end end end
Vòng lặp bên ngoài lặp qua các dòng của bàn cờ, từ 0 đến _BanCo.SoDong - 1.
Vòng lặp bên trong lặp qua các cột của bàn cờ, từ 0 đến _BanCo.SoCot - 1.
Trong mỗi lần lặp, một đối tượng mới của lớp OCo được tạo ra với các tham
i: chỉ số dòng của ô cờ
j: chỉ số cột của ô cờ
new Point(j * OCo._ChieuRong, i * OCo._ChieuCao): tọa độ của ô cờ dựa trên chiều rộng và chiều cao của mỗi ô
0: giá trị khởi tạo của ô cờ
Các đối tượng OCo được lưu vào mảng _MangOCo tại vị trí tương ứng với dòng và cột của từng ô cờ.
3.1.2 Đánh cờ 3.1.2.1 Sơ đồ thuật toán
- Hàm vẽ quân cờ: function VeQuanCo(g: Graphics, point: Point, sb: SolidBrush) begin g.FillEllipse(sb, point.X + 2, point.Y + 2, OCo._ChieuRong - 4, OCo._ChieuCao - 4) end
Phương thức VeQuanCo nhận ba tham số:
g: một đối tượng Graphics để vẽ lên
point: một đối tượng Point chứa tọa độ của ô cờ để vẽ quân cờ
sb: một đối tượng SolidBrush chứa màu sắc để vẽ quân cờ
Phương thức sử dụng g.FillEllipse() để vẽ một hình ellipse (quân cờ) tại tọa độ (point.X + 2, point.Y + 2) với kích thước (OCo._ChieuRong - 4,
Việc trừ 4 ở cả hai chiều rộng và chiều cao là để tạo khoảng cách giữa viền của ô cờ và quân cờ, tạo ra một quân cờ có kích thước nhỏ hơn so với kích thước của ô cờ.
Màu sắc của quân cờ được xác định bởi đối tượng SolidBrush sb được truyền vào.
- Hàm đánh cờ function Danhco(MouseX, MouseY, g): if MouseX % OCo._ChieuRong == 0: return false
Cot = MouseX / OCo._ChieuRong Dong = MouseY / OCo._ChieuCao if _MangOCo[Dong, Cot].Sohuu != 0: return false switch _LuotDi: case 1:
_MangOCo[Dong, Cot].Sohuu = 1 _BanCo.VeQuanCo(g, _MangOCo[Dong, Cot].ViTri, sbBlue) _LuotDi = 2 case 2:
_MangOCo[Dong, Cot].Sohuu = 2 _BanCo.VeQuanCo(g, _MangOCo[Dong, Cot].ViTri, sbRed) _LuotDi = 1 default: show_message_box("Có lỗ? i") stk_CacNuocUndo = new Stack() stk_CacNuocDaDi.push(oco) return true
Kiểm tra xem vị trí click của chuột có hợp lệ không (không trùng với đường ô cờ).
Tính toán vị trí của ô cờ được click dựa trên tọa độ chuột.
Kiểm tra xem ô cờ đó đã được sở hữu bởi một quân cờ nào chưa.
Dựa trợn lượt đi hiện tại, gán sở hữu ô cờ cho người chơi tương ứng và vẽ quân cờ lên bàn cờ.
Thay đổi lượt đi cho lần tiếp theo.
Lưu lại nước đi vừa được thực hiện vào stack stk_CacNuocDaDi.
- Hàm cập nhật lại bàn cờ (bàn cờ được vẽ lại sau mỗi lượt đánh) function VeLaiQuanCo(g): foreach oco in stk_CacNuocDaDi: if oco.Sohuu == 1:
_BanCo.VeQuanCo(g, oco.ViTri, sbBlue) else if oco.Sohuu == 2:
_BanCo.VeQuanCo(g, oco.ViTri, sbRed)
Duyệt qua tất cả các nước đã đi trong stack stk_CacNuocDaDi.
Đối với mỗi nước đã đi:
Nếu quân cờ đó thuộc về người chơi 1 (Sohuu = 1), vẽ quân cờ xanh lam tại vị trí tương ứng.
Nếu quân cờ đó thuộc về người chơi 2 (Sohuu = 2), vẽ quân cờ đỏ tại vị trí tương ứng.
Chức năng PlayerVsPlayer
- Khởi tạo chế độ chơi
_SanSang = true stk_CacNuocDaDi = new Stack() stk_CacNuocUndo = new Stack() _LuotDi = 1
Hàm bắt đầu bằng việc gán giá trị true cho biến _SanSang, điều này cho biết rằng trò chơi đã sẵn sàng.
Hai stack stk_CacNuocDaDi và stk_CacNuocUndo được khởi tạo, để lưu trữ các nước đi trong trò chơi.
Biến _LuotDi được gán giá trị 1, cho biết lượt đi của người chơi đầu tiên.
Biến _CheDoChoi được gán giá trị 1, cho biết chế độ chơi là người chơi vs người chơi.
Hàm KhoiTaoMangOCo() được gọi để khởi tạo mảng các ô cờ.
Hàm VeBanCo(g) được gọi để vẽ bàn cờ lên màn hình.
Chức năng PlayerVsCom
- Khởi tạo chế độ chơi
_SanSang = true stk_CacNuocDaDi = new Stack() stk_CacNuocUndo = new Stack() _LuotDi = 1
Hàm bắt đầu bằng việc gán giá trị true cho biến _SanSang, điều này cho biết rằng trò chơi đã sẵn sàng.
Hai stack stk_CacNuocDaDi và stk_CacNuocUndo được khởi tạo, để lưu trữ các nước đi trong trò chơi.
Biến _LuotDi được gán giá trị 1, cho biết lượt đi của người chơi đầu tiên.
Biến _CheDoChoi được gán giá trị 2, cho biết chế độ chơi là người chơi vs máy.
Hàm KhoiTaoMangOCo() được gọi để khởi tạo mảng các ô cờ.
Hàm VeBanCo(g) được gọi để vẽ bàn cờ lên màn hình.
Hàm KhoiDongComputer(g) được gọi để khởi động máy tính và bắt đầu chơi.
Mã giả function KhoiDongComputer(g): if stk_CacNuocDaDi.Count == 0: x = _BanCo.SoCot / 2 * OCo._ChieuRong + 1 y = _BanCo.SoDong / 2 * OCo._ChieuCao + 1 Danhco(x, y, g) else: oco = TimKiemNuocDi() x = oco.ViTri.X + 1 y = oco.ViTri.Y + 1 Danhco(x, y, g)
Hàm bắt đầu bằng việc kiểm tra xem stack stk_CacNuocDaDi có phải là rỗng hay không.
Nếu stack là rỗng, tức là chưa có nước đi nào, thì máy sẽ đánh vào vị trí trung tâm của bàn cờ:
Tính toán tọa độ x và y của vị trí trung tâm.
Gọi hàm Danhco(x, y, g) để đánh cờ vào vị trí đó.
Nếu stack không rỗng, tức là đã có nước đi trước đó, thì máy sẽ tìm kiếm nước đi tối ưu tiếp theo bằng cách gọi hàm TimKiemNuocDi():
Lấy ô cờ mà hàm TimKiemNuocDi() trả về.
Tính toán tọa độ x và y của vị trí ô cờ.
Gọi hàm Danhco(x, y, g) để đánh cờ vào vị trí đó.
Mã giả function DiemTanCong_DuyetDoc(currDong, currCot):
# Duyệt vềJ phía trền Dem = 1 while Dem < 6 and currDong + Dem < _BanCo.SoDong: if _MangOCo[currDong + Dem, currCot].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong + Dem, currCot].Sohuu == 2:
SoQuanDich += 1 break else: break Dem += 1
# Duyệt vềJ phía dưới Dem = 1 while Dem < 6 and currDong - Dem >= 0: if _MangOCo[currDong - Dem, currCot].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong - Dem, currCot].Sohuu == 2:
SoQuanDich += 1 break Dem += 1 if SoQuanDich == 2: return 0
DiemTong -= MangDiemPhongNgu[SoQuanDich + 1] * 2 DiemTong += MangDiemTanCong[SoQuanTa] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt về phía trên từ vị trí currDong đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt về phía dưới từ vị trí currDong đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanDich bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm tấn công bằng cách:
Trừ đi MangDiemPhongNgu[SoQuanDich + 1] * 2 để tính điểm phòng ngự.
Cộng thêm MangDiemTanCong[SoQuanTa] để tính điểm tấn công.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemTanCong_DuyetNgang(currDong, currCot):
# Duyệt vềJ phía bền pha Oi Dem = 1 while Dem < 6 and currCot + Dem < _BanCo.SoCot: if _MangOCo[currDong, currCot + Dem].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong, currCot + Dem].Sohuu == 2:
SoQuanDich += 1 break else: break Dem += 1
# Duyệt vềJ phía bền trái Dem = 1 while Dem < 6 and currCot - Dem >= 0: if _MangOCo[currDong, currCot - Dem].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong, currCot - Dem].Sohuu == 2:
SoQuanDich += 1 break else: break Dem += 1 if SoQuanDich == 2: return 0
DiemTong -= MangDiemPhongNgu[SoQuanDich + 1] * 2 DiemTong += MangDiemTanCong[SoQuanTa] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt về phía bên phải từ vị trí currCot đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt về phía bên trái từ vị trí currCot đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanDich bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm tấn công bằng cách:
Trừ đi MangDiemPhongNgu[SoQuanDich + 1] * 2 để tính điểm phòng ngự.
Cộng thêm MangDiemTanCong[SoQuanTa] để tính điểm tấn công.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemTanCong_DuyetCheoXuoi(currDong, currCot):
# Duyệt vềJ đường chéo xuỗi Dem = 1 while Dem < 6 and currCot + Dem < _BanCo.SoCot and currDong + Dem
< _BanCo.SoDong: if _MangOCo[currDong + Dem, currCot + Dem].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong + Dem, currCot + Dem].Sohuu == 2:
SoQuanDich += 1 break else: break Dem += 1
# Duyệt vềJ đường chéo ngược Dem = 1 while Dem < 6 and currCot - Dem >= 0 and currDong - Dem >= 0: if _MangOCo[currDong - Dem, currCot - Dem].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong - Dem, currCot - Dem].Sohuu == 2:
SoQuanDich += 1 break else: break Dem += 1 if SoQuanDich == 2: return 0
DiemTong -= MangDiemPhongNgu[SoQuanDich + 1] * 2 DiemTong += MangDiemTanCong[SoQuanTa] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt về đường chéo xuôi từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt về đường chéo ngược từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanDich bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm tấn công bằng cách:
Trừ đi MangDiemPhongNgu[SoQuanDich + 1] * 2 để tính điểm phòng ngự.
Cộng thêm MangDiemTanCong[SoQuanTa] để tính điểm tấn công.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemTanCong_DuyetCheoNguoc(currDong, currCot):
# Duyệt vềJ đường chéo ngược Dem = 1 while Dem < 6 and currCot + Dem < _BanCo.SoCot and currDong - Dem
>= 0: if _MangOCo[currDong - Dem, currCot + Dem].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong - Dem, currCot + Dem].Sohuu == 2: break Dem += 1
# Duyệt vềJ đường chéo xuỗi Dem = 1 while Dem < 6 and currCot - Dem >= 0 and currDong + Dem <
_BanCo.SoDong: if _MangOCo[currDong + Dem, currCot - Dem].Sohuu == 1:
SoQuanTa += 1 elif _MangOCo[currDong + Dem, currCot - Dem].Sohuu == 2:
SoQuanDich += 1 break else: break Dem += 1 if SoQuanDich == 2: return 0
DiemTong -= MangDiemPhongNgu[SoQuanDich + 1] * 2 DiemTong += MangDiemTanCong[SoQuanTa] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt về đường chéo ngược từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt về đường chéo xuôi từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân địch:
Nếu gặp quân ta, tăng SoQuanTa lên 1.
Nếu gặp quân địch, tăng SoQuanDich lên 1 và kết thúc vòng lặp.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanDich bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm tấn công bằng cách:
Trừ đi MangDiemPhongNgu[SoQuanDich + 1] * 2 để tính điểm phòng ngự.
Cộng thêm MangDiemTanCong[SoQuanTa] để tính điểm tấn công.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemPhongNgu_DuyetDoc(currDong, currCot):
# Duyệt vềJ phía dưới Dem = 1 while Dem < 6 and currDong + Dem < _BanCo.SoDong: if _MangOCo[currDong + Dem, currCot].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong + Dem, currCot].Sohuu == 2:
# Duyệt vềJ phía trền Dem = 1 while Dem < 6 and currDong - Dem >= 0: if _MangOCo[currDong - Dem, currCot].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong - Dem, currCot].Sohuu == 2:
SoQuanDich += 1 else: break Dem += 1 if SoQuanTa == 2: return 0 DiemTong += MangDiemPhongNgu[SoQuanDich] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt về phía dưới từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt về phía trên từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân ta, tăng SoQuanTa lên 1 và kết thúc vòng lặp.
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanTa bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm phòng ngự bằng cách cộng thêm MangDiemPhongNgu[SoQuanDich] vào DiemTong.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemPhongNgu_DuyetNgang(currDong, currCot):
# Duyệt sang pha Oi Dem = 1 while Dem < 6 and currCot + Dem < _BanCo.SoCot: if _MangOCo[currDong, currCot + Dem].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong, currCot + Dem].Sohuu == 2:
# Duyệt sang trái Dem = 1 while Dem < 6 and currCot - Dem >= 0: if _MangOCo[currDong, currCot - Dem].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong, currCot - Dem].Sohuu == 2:
SoQuanDich += 1 else: break Dem += 1 if SoQuanTa == 2: return 0 DiemTong += MangDiemPhongNgu[SoQuanDich] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt sang phải từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân ta, tăng SoQuanTa lên 1 và kết thúc vòng lặp.
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt sang trái từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân ta, tăng SoQuanTa lên 1 và kết thúc vòng lặp.
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanTa bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm phòng ngự bằng cách cộng thêm MangDiemPhongNgu[SoQuanDich] vào DiemTong.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemPhongNgu_DuyetCheoXuoi(currDong, currCot):
# Duyệt đường chéo xuỗi Dem = 1 while Dem < 6 and currCot + Dem < _BanCo.SoCot and currDong + Dem
< _BanCo.SoDong: if _MangOCo[currDong + Dem, currCot + Dem].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong + Dem, currCot + Dem].Sohuu == 2:
# Duyệt đường chéo ngược Dem = 1 while Dem < 6 and currCot - Dem >= 0 and currDong - Dem >= 0: if _MangOCo[currDong - Dem, currCot - Dem].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong - Dem, currCot - Dem].Sohuu == 2:
SoQuanDich += 1 else: break Dem += 1 if SoQuanTa == 2: return 0 DiemTong += MangDiemPhongNgu[SoQuanDich] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt đường chéo xuôi từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân ta, tăng SoQuanTa lên 1 và kết thúc vòng lặp.
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt đường chéo ngược từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân ta, tăng SoQuanTa lên 1 và kết thúc vòng lặp.
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanTa bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm phòng ngự bằng cách cộng thêm MangDiemPhongNgu[SoQuanDich] vào DiemTong.
6 Trả về điểm tổng DiemTong.
Mã giả function DiemPhongNgu_DuyetCheoNguoc(currDong, currCot):
# Duyệt đường chéo ngược Dem = 1 while Dem < 6 and currCot + Dem < _BanCo.SoCot and currDong - Dem
>= 0: if _MangOCo[currDong - Dem, currCot + Dem].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong - Dem, currCot + Dem].Sohuu == 2:
# Duyệt đường chéo xuỗi Dem = 1 while Dem < 6 and currCot - Dem >= 0 and currDong + Dem <
_BanCo.SoDong: if _MangOCo[currDong + Dem, currCot - Dem].Sohuu == 1:
SoQuanTa += 1 break elif _MangOCo[currDong + Dem, currCot - Dem].Sohuu == 2:
SoQuanDich += 1 else: break Dem += 1 if SoQuanTa == 2: return 0 DiemTong += MangDiemPhongNgu[SoQuanDich] return DiemTong
Giải thích 1 Khởi tạo các biến DiemTong, SoQuanTa và SoQuanDich.
2 Tiến hành duyệt đường chéo ngược từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân ta, tăng SoQuanTa lên 1 và kết thúc vòng lặp.
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
3 Tiến hành duyệt đường chéo xuôi từ vị trí currDong và currCot cho đến khi gặp biên hoặc quân ta:
Nếu gặp quân địch, tăng SoQuanDich lên 1.
Nếu gặp ô trống, kết thúc vòng lặp.
4 Kiểm tra nếu SoQuanTa bằng 2 thì trả về 0, vì đây là trường hợp bị chặn.
5 Tính điểm phòng ngự bằng cách cộng thêm MangDiemPhongNgu[SoQuanDich] vào DiemTong.
6 Trả về điểm tổng DiemTong.
- Tìm kiến nước đi của máy
Mã giả private OCo TimKiemNuocDi() {
OCo oCoResult = new OCo(); long DiemMax = 0; for (int i = 0; i < _BanCo.SoDong; i++) { for (int j = 0; j < _BanCo.SoCot; j++) { if (_MangOCo[i, j].Sohuu == 0) { long DiemTanCong = DiemTanCong_DuyetDoc(i, j) + DiemTanCong_DuyetNgang(i, j) + DiemTanCong_DuyetCheoXuoi(i, j) + DiemTanCong_DuyetCheoNguoc(i, j); long DiemPhongNgu = DiemPhongNgu_DuyetDoc(i, j) + DiemPhongNgu_DuyetNgang(i, j) + DiemPhongNgu_DuyetCheoXuoi(i, j) + DiemPhongNgu_DuyetCheoNguoc(i, j); long DiemTam = DiemTanCong > DiemPhongNgu ? DiemTanCong : DiemPhongNgu; if (DiemMax < DiemTam) {
DiemMax = DiemTam; oCoResult = new OCo(_MangOCo[i, j].Dong, _MangOCo[i, j].Cot, _MangOCo[i, j].ViTri, _MangOCo[i, j].Sohuu);
Phương thức này tìm ô có điểm số tấn công và phòng ngự cao nhất trên bàn cờ và trả về ô đó.
Nó sử dụng các phương thức khác để tính toán điểm tấn công và phòng ngự cho mỗi ô trên bàn cờ, sau đó so sánh và tìm ra ô có điểm số cao nhất.
- Duyệt các phương thẳng hàng
1 Duyệt phương dọc Mã giả function DuyetDoc(currDong, currCot, currSoHuu): if currDong > _BanCo.SoDong - 5: return false for Dem = 1 to 4: if _MangOCo[currDong + Dem, currCot].Sohuu != currSoHuu: return false if currDong == 0 or currDong + Dem == _BanCo.SoDong: return true if _MangOCo[currDong - 1, currCot].Sohuu == 0 or _MangOCo[currDong + Dem, currCot].Sohuu == 0: return true return false
Kiểm tra xem nếu currDong vượt quá _BanCo.SoDong - 5 thì trả về false.
Sau đó, duyệt 4 ô liên tiếp từ currDong đến currDong + 4 Nếu bất kỳ ô nào không có chủ sở hữu giống với currSoHuu, thì trả về false.
Nếu currDong là 0 hoặc currDong + Dem bằng _BanCo.SoDong, thì trả về true.
Nếu ô trên hoặc dưới dãy 5 ô không có chủ sở hữu, thì trả về true.
Nếu tất cả các điều kiện trên không thỏa mãn, thì trả về false.
2 Duyệt phương ngang Mã giả function DuyetNgang(currDong, currCot, currSoHuu): for Dem = 1 to 4: if _MangOCo[currDong, currCot + Dem].Sohuu != currSoHuu: return false if currCot == 0 or currCot + Dem == _BanCo.SoCot: return true if _MangOCo[currDong, currCot - 1].Sohuu == 0 or _MangOCo[currDong, currCot + Dem].Sohuu == 0: return true return false
Kiểm tra xem nếu currCot vượt quá _BanCo.SoCot - 5 thì trả về false.
Sau đó, duyệt 4 ô liên tiếp từ currCot đến currCot + 4 Nếu bất kỳ ô nào không có chủ sở hữu giống với currSoHuu, thì trả về false.
Nếu currCot là 0 hoặc currCot + Dem bằng _BanCo.SoCot, thì trả về true.
Nếu ô bên trái hoặc bên phải dãy 5 ô không có chủ sở hữu, thì trả về true.
Nếu tất cả các điều kiện trên không thỏa mãn, thì trả về false.
3 Duyệt phương chéo xuôi Mã giả function DuyetCheoXuoi(currDong, currCot, currSoHuu): if currDong > _BanCo.SoCot - 5 or currCot > _BanCo.SoCot - 5: return false for Dem = 1 to 4: if _MangOCo[currDong + Dem, currCot + Dem].Sohuu != currSoHuu: return false if currDong == 0 or currDong + Dem == _BanCo.SoDong or currCot == 0 or currCot + Dem == _BanCo.SoCot: return true if _MangOCo[currDong - 1, currCot - 1].Sohuu == 0 or _MangOCo[currDong + Dem, currCot + Dem].Sohuu == 0: return true return false
Kiểm tra xem nếu currDong hoặc currCot vượt quá _BanCo.SoCot - 5 thì trả về false.
Sau đó, duyệt 4 ô liên tiếp đường chéo từ currDong đến currDong + 4 và từ currCot đến currCot + 4 Nếu bất kỳ ô nào không có chủ sở hữu giống với currSoHuu, thì trả về false.
Nếu currDong là 0 hoặc currDong + Dem bằng _BanCo.SoDong, hoặc currCot là 0 hoặc currCot + Dem bằng _BanCo.SoCot, thì trả về true.
Nếu ô trên trái hoặc dưới phải dãy 5 ô không có chủ sở hữu, thì trả về true.
Nếu tất cả các điều kiện trên không thỏa mãn, thì trả về false.
4 Duyệt phương chéo ngược Mã giả function DuyetCheoNguoc(currDong, currCot, currSoHuu): if currDong < 4 or currCot > _BanCo.SoCot - 5: return false for Dem = 1 to 4: if _MangOCo[currDong - Dem, currCot + Dem].Sohuu != currSoHuu: return false if currDong == 4 or currDong == _BanCo.SoDong - 1 or currCot == 0 or currCot + Dem == _BanCo.SoCot: return true if _MangOCo[currDong + 1, currCot - 1].Sohuu == 0 or _MangOCo[currDong - Dem, currCot + Dem].Sohuu == 0: return true return false
Đầu tiên, hàm kiểm tra xem nếu currDong nhỏ hơn 4 hoặc currCot lớn hơn _BanCo.SoCot - 5, thì trả về false Điều này đảm bảo rằng có đủ ô để kiểm tra đường chéo ngược.
Tiếp theo, hàm duyệt 4 ô liên tiếp đường chéo ngược từ currDong đến currDong - 4 và từ currCot đến currCot + 4 Nếu bất kỳ ô nào không có
Nếu currDong bằng 4 hoặc currDong bằng _BanCo.SoDong - 1, hoặc currCot bằng 0 hoặc currCot + Dem bằng _BanCo.SoCot, thì trả về true.
Nếu ô trên phải hoặc dưới trái dãy 5 ô không có chủ sở hữu, thì trả về true.
Nếu tất cả các điều kiện trên không thỏa mãn, thì trả về false.
Mã giả function KiemTraChienThang(): if length(stk_CacNuocDaDi) == _BanCo.SoCot * _BanCo.SoDong:
_KetThuc = KETTHUC.HoaCO return true if CheDoChoi == 1: for each oco in stk_CacNuocDaDi: if DuyetDoc(oco.Dong, oco.Cot, oco.Sohuu) or DuyetNgang(oco.Dong, oco.Cot, oco.Sohuu) or
DuyetCheoXuoi(oco.Dong, oco.Cot, oco.Sohuu) or DuyetCheoNguoc(oco.Dong, oco.Cot, oco.Sohuu): if oco.Sohuu == 1:
_KetThuc = KETTHUC.Player2 return true if CheDoChoi == 2: for each oco in stk_CacNuocDaDi: if DuyetDoc(oco.Dong, oco.Cot, oco.Sohuu) or DuyetNgang(oco.Dong, oco.Cot, oco.Sohuu) or
DuyetCheoXuoi(oco.Dong, oco.Cot, oco.Sohuu) or DuyetCheoNguoc(oco.Dong, oco.Cot, oco.Sohuu): if oco.Sohuu == 1:
_KetThuc = KETTHUC.Player return true return false
Đầu tiên, hàm kiểm tra xem số lượng nước đã đi có bằng với số ô trên bàn cờ hay không Nếu có, thì trò chơi kết thúc với kết quả hòa và _KetThuc được gán giá trị KETTHUC.HoaCO.
Nếu chế độ chơi là 1 (người vs người), hàm lặp qua tất cả các nước đã đi và kiểm tra xem có ô nào thỏa mãn một trong 4 hàm kiểm tra (dọc, ngang, chéo xuôi, chéo ngược) hay không Nếu có, thì _KetThuc được gán giá trị KETTHUC.Player1 hoặc KETTHUC.Player2 tùy theo chủ sở hữu của ô đó.
Nếu chế độ chơi là 2 (người vs máy), hàm cũng lặp qua tất cả các nước đã đi và kiểm tra xem có ô nào thỏa mãn một trong 4 hàm kiểm tra hay không Nếu có, thì _KetThuc được gán giá trị KETTHUC.COM hoặc KETTHUC.Player tùy theo chủ sở hữu của ô đó.
Nếu không tìm thấy ô nào thỏa mãn các điều kiện trên, hàm trả về false.
Mã giả function KetThucTroChoi(): switch _KetThuc: case KETTHUC.HoaCO: show message "Hoa co!" case KETTHUC.Player1: show message "Nguoi choi xanh thang!" case KETTHUC.Player2: show message "Nguoi choi do thang!" case KETTHUC.Player: show message "Nguoi choi thang!" case KETTHUC.COM: show message "Computer thang!"
Hàm bắt đầu bằng một câu lệnh switch để kiểm tra giá trị của biến _KetThuc.
Tùy theo giá trị của _KetThuc, hàm sẽ hiển thị một thông báo tương ứng với kết quả của trò chơi.
Nếu _KetThuc là KETTHUC.HoaCO, sẽ hiển thị thông báo "Hoa co!".
Nếu _KetThuc là KETTHUC.Player1, sẽ hiển thị thông báo "Nguoi choi xanh thang!".
Nếu _KetThuc là KETTHUC.Player2, sẽ hiển thị thông báo "Nguoi choi do thang!".
Nếu _KetThuc là KETTHUC.Player, sẽ hiển thị thông báo "Nguoi choi thang!".
Nếu _KetThuc là KETTHUC.COM, sẽ hiển thị thông báo
Cuối cùng, biến _SanSang được gán giá trị false để chỉ ra rằng trò chơi đã kết thúc.