1 Player Click vào nút back 2 System Đóng cửa sổ PlayGame và hiện cửa sổ với giao diện MainMenu 3 Player Click vào 1 ô bất kỳ trên bản 6 System Kiểm tra xem có tàu nào bị hạ hoàn toàn ch
KHẢO SÁT, ĐẶC TẢ YÊU CẦU BÀI TOÁN
Mô tả yêu cầu bài toán
Xây dựng trò chơi bắn tàu, cho phép người chơi chơi với máy, bao gồm các chức năng chính:
+ Cho phép người chơi lựa chọn tàu chiến, sắp xếp đội hình (mỗi loại tàu chiến có kích thước và điểm số khác nhau)
+ Đánh dấu tọa độ bắn trật , bắn trúng của mỗi lượt chơi
Chức năng này cho phép lưu lại kết quả điểm số đạt được (điểm số và số lần người chơi đã thực hiện dự đoán) và lịch sử trận chiến (các bước dự đoán của người chơi và kết quả bắn trúng hoặc bắn trượt), giúp theo dõi hiệu suất và phân tích chiến thuật một cách dễ dàng.
+ Xây dựng thuật toán cho máy chơi ở hai mức độ dễ và khó
+ Cấu hình game: tắt bật âm thanh / âm nhạc / reset điểm số
Biểu đồ use case
1.2.1 Biểu đồ use case tổng quan
1.2.2 Biểu đồ use case phân rã mức 2
Phân rã use case Start, ta được các use case:
Phân rã use case Prepare, ta được các use case
Phân tích use case Fight, ta được các use case:
Đặc tả use case
- Đặc tả use case Start
Mã UC (UC #) BS007 Tên usecase Start
Tác nhân Người chơi (Player) Điều kiện trước Người chơi chạy chương trình
No Thực hiện Hành động
1 Player Click vào nút easy/ hard
2 System Thay đổi chế độ chơi khó / dễ
3 Player Click vào nút GameRule
4 System Hiển thị hướng dẫn chơi
5 Player Click vào nút HighScore
6 System Hiển thị màn hình lịch sử điểm cao
7 Player Click vào nút Sound on/ off
8 System Bật/ tắt âm thanh
9 Player Click vào nút Play
10 System Khởi tạo giao diện sắp xếp tàu lên bản đồ
11 Player Click vào nút Exit
12 System Thoát khỏi chương trình Điều kiện sau Người chơi ấn nút Play
- Đặc tả use case Prepare
Mã UC (UC #) BS008 Tên usecase Prepare
Tác nhân Người chơi (Player) Điều kiện trước Người chơi click vào nút Play ở giao diện MainMenu
No Thực hiện Hành động
1 Player Kéo tàu từ container chứa tàu vào trong Map
2 System Hiển thị vị trí tàu người chơi kéo
3 Player vàoKéo tàu từ vị trí cũ đến vị trí mới trong Map
4 System Hiển thị vị trí tàu người chơi vừa kéo thả
5 Player Click vào nút auto
6 System Sắp xếp tàu ở container vào trong
Map một cách ngẫu nhiên
7 Player Click vào nút back
8 System Khởi tạo giao diện MainMenu
9 Player Click vào nút ready
10 System Khởi tạo giao diện PlayGame
Luồng thực thi mở rộng
Hệ thống đổi hướng tàu được kích hoạt khi người chơi nhấn chuột phải, giúp tàu lập tức chuyển hướng; đồng thời nếu người chơi thả tàu ở ngoài bản đồ hoặc thả tàu vào tàu khác, tàu sẽ được trả về vị trí cũ trên bản đồ Điều kiện áp dụng cho toàn bộ hệ thống là tất cả các tàu đều được xếp lên bản đồ.
- Đặc tả use case Fight
Mã UC (UC #) BS009 Tên usecase Fight
Người chơi là tác nhân chính của trò chơi Điều kiện trước khi bắt đầu trận đấu là người chơi phải nhấp vào nút ready trong giao diện xếp tàu và đảm bảo tất cả tàu đã được sắp xếp lên bản đồ (map) Khi các điều kiện này được đáp ứng, trạng thái sẵn sàng được kích hoạt để trận đấu có thể bắt đầu trên bảng đồ.
No Thực hiện Hành động
1 Player Click vào nút back
2 System Đóng cửa sổ PlayGame và hiện cửa sổ với giao diện MainMenu
3 Player Click vào 1 ô bất kỳ trên bản
4 System đồ.Kiểm tra ô đó đã được đánh hay chưa.
5 System Kiểm tra ô được chọn có tàu hay không
6 System Kiểm tra xem có tàu nào bị hạ hoàn toàn chưa
7 System Kiểm tra người chơi hoặc máy đã thắng chưa
8 System Chọn 1 ô ngẫu nhiên để bắn tàu người chơi
9 Player Click nút “Play Again” khi player hoặc máy đã thắng
10 System Lưu kết quả điểm số của người chơi vào dữ liệu điểm
11 System Quay trở về Menu
12 Player Click nút Highscore khi player hoặc máy đã thắng
13 System Hiển thị màn hình lịch sử điểm cao
Luồng thực thi mở rộng
4a System Không thực hiện gì nếu ô được chọn đã được chọn trước đó.
Trong hệ thống 4b, khi ô chưa được chọn sẽ thực hiện luồng thực thi số 5 Trong luồng thực thi 5a, nếu ô không có tàu, hệ thống sẽ đổi ô đó thành biểu tượng ô màu trắng để biểu thị trạng thái không có tàu và sau đó thực hiện luồng thực thi số 8.
5b System Nếu ô có tàu, thay đổi biểu tượng ô thành hình ảnh ô màu đỏ, thực hiện luồng thực thi 6
Luồng xử lý hệ thống bắt đầu từ 6a: nếu chưa thực hiện, hệ thống thực hiện luồng thực thi 8; nếu đã thực hiện ở 6b, hệ thống thay hình ảnh các ô tại vị trí con tàu bằng hình ảnh của con tàu và thực hiện luồng thực thi 7; tại 7a, nếu chưa thực hiện, tiếp tục thực hiện luồng thực thi 8; tại 7b, nếu đã thực hiện, hệ thống hiển thị kết quả của người chơi và cho người chơi chọn trở về menu hoặc xem lịch sử điểm cao; cuối cùng, tại 8a, hệ thống thực hiện luồng thực thi 4.
10a System Nếu điểm của người chơi cao hơn 1 số điểm cao trong dữ liệu thì cập nhật lại điểm cao
10b System Nếu điểm người chơi thấp hơn các điểm cao thì không cập nhật.
13a System Nếu người chơi ấn nút reset, xóa lịch sử điểm cao
13b System Quay về giao diện của
MainMenu nếu người chơi ấn nút back Điều kiện sau Người chơi xem điểm cao hoặc quay về gia diện MainMenu
PHÂN TÍCH THIẾT KẾ BÀI TOÁN
Thiết kế Cơ sở dữ liệu hoặc Cấu trúc tệp dữ liệu
Biểu đồ trình tự
-Biểu đồ trình tự của use case Prepare
-Biểu đồ trình tự của use case Fight
Biểu đồ lớp
- Các lớp trong chương trình:
Thiết kế chi tiết lớp
Phân tích: để giải quyết bài toán này chúng ta xây dựng 8 lớp:
Lớp Ship : chứa hình ảnh của các con tàu với các kích thước khác nhau
Lớp Map là một bản đồ kích thước 10x10, trong đó mỗi ô thuộc lớp Map đại diện cho một phần tử của bản đồ Lớp MainMenu hiển thị giao diện menu cho người chơi với các tùy chọn như bật/tắt âm thanh, chọn chế độ chơi (dễ hay khó), xem điểm cao, bắt đầu trò chơi, thoát trò chơi và hướng dẫn chơi.
Lớp HighScore hiển thị điểm cao mà người chơi đã đạt được; nếu muốn xóa điểm cao, người chơi nhấn nút reset, còn nút back để quay về MainMenu Lớp Creator cung cấp khung hiển thị các tàu chiến và bản đồ để người chơi có thể đặt tàu lên vị trí mong muốn; ngoài ra còn có nút Auto để tự động sắp xếp tàu ở vị trí ngẫu nhiên.
Lớp PlayGame hiển thị hai bản đồ: bản đồ của người chơi và bản đồ của máy Người chơi chọn tọa độ để bắn trên bản đồ của máy, trong khi máy sẽ bắn trên bản đồ của người chơi được cấu hình từ Creator Đồng thời PlayGame hiển thị các thông số trận đấu như vị trí đã bắn và kết quả bắn trúng hay bắn trượt, giúp người chơi nắm được diễn biến lượt chơi và chiến thuật trong trò chơi.
Lớp EndScreen hiển thị số điểm của người chơi và kết quả thắng thua, đồng thời phát âm thanh để tăng trải nghiệm Giao diện EndScreen cung cấp hai nút chính là Highscore để vào HighScore và Play Again để quay về MainMenu, cho phép người chơi xem thành tích hoặc bắt đầu lại trận đấu ngay lập tức.
Lớp BattleShip : khởi tạo đối tượng MainMenu để bắt đầu thực thi trò chơi.
Chứa hình ảnh của các con tàu (ship: Image) với chiều dài 1,2,3,4,5 (chiều dài tính theo số ô trên bản đồ, 1 ô tương đương với chiều dài là 1)
Lớp ship cung cấp một phương thức khởi tạo nhận tham số truyền vào là (length, w, h, isNgang); trong đó length đại diện cho chiều dài con tàu trên bản đồ, w và h lần lượt là chiều rộng và chiều cao của hình ảnh con tàu được hiển thị trên màn hình người chơi, và isNgang xác định tàu ở chế độ ngang hay dọc Việc khởi tạo đúng tham số giúp hệ thống quản lý vị trí, kích thước và hướng hiển thị của tàu trên giao diện trò chơi một cách nhất quán.
- Phương thức rotateShip() với 4 tham số truyền vào là (length, w, h, isNgang) để lấy đường dẫn tương ứng với tàu ngang hay dọc và theo chiều dài của tàu
- Phương thức loadImage() với 3 tham số truyền vào (s,w,h): trả về hình ảnh được lấy từ đường dẫn s và được ép kích thước sang (w,h).
Lớp này kế thừa lớp JPanel, bao gồm các thành phần:
- Mảng mapPiece[][] với kiểu dữ liệu là JButton, đây là mảng có kích thước 10x10, ứng với 10x10 ô trên bản đồ
- Mảng boolean isShip[][]: đánh dấu xem ô (i,j) trên bản đồ có tàu ở đó hay không. Lớp Map có 1 phương thức khởi tạo:
Trong constructor nhận hai tham số w, h tương ứng với kích thước dài và rộng của bản đồ, hệ thống khởi tạo hai mảng mapPiece và isShip; mapPiece được thêm vào JPanel để hiển thị các nút bấm trên bản đồ, phục vụ cho người chơi trong quá trình chơi Phương thức init() khởi tạo mảng isShip ban đầu là false, để đánh dấu các ô trên bản đồ chưa xuất hiện tàu nào.
Lớp Menu đảm nhận nhiệm vụ hiển thị Menu với các lựa chọn dành cho người chơi như bắt đầu chơi, bật/tắt âm thanh, chọn chế độ chơi (dễ/khó), xem điểm cao, thoát khỏi trò chơi và xem hướng dẫn chơi Giao diện Menu được xây dựng với một JFrame để chứa màn hình lựa chọn cho người chơi; JFrame gồm một JLabel tên menu1 chứa các nút (button) tương ứng với từng chức năng nhằm người chơi có thể tương tác dễ dàng.
+ PLAY: khởi tạo đối tượng của Creator, màn hình xếp tàu được hiện ra để người chơi sắp xếp đội hình
+ EASY/HARD: chọn chế độ khó/ dễ (nếu button hiển thị là easy -> chế độ dễ, hard -> chế độ khó)
+ GAME RULE: hiển thị hướng dẫn luật chơi
+ HIGHSCORE: hiển thị lịch sử điểm cao
+ SOUND OFF/ON: bật/ tắt âm thanh
+ EXIT: thoát khỏi chương trình
Lớp MainMenu chứa hai đối tượng quan trọng: một đối tượng của lớp Creator và một đối tượng của lớp HighScore Đối tượng Creator được khởi tạo khi người chơi nhấn nút Play, trong khi đối tượng HighScore được khởi tạo khi người chơi nhấn nút HighScore.
Trong lớp MainMenu, biến clip với kiểu dữ liệu Clip đảm nhận chức năng phát âm thanh trong trò chơi, cho phép phát nhạc và âm thanh hiệu ứng khi người chơi tương tác Biến static isPlaySound có kiểu boolean được sử dụng để nhận biết trạng thái âm thanh đang bật hay tắt và điều chỉnh việc phát âm thanh cho trò chơi một cách nhất quán.
Lớp này cung cấp một phương thức khởi tạo nhận tham số lần lượt là w, h và playSound; w và h đại diện cho chiều rộng và chiều cao của frame, còn playSound là biến boolean cho biết âm thanh có đang bật hay tắt (isPlaySound = playSound) Trong quá trình khởi tạo, màn hình menu1 được khởi tạo trước, đồng thời nếu người chơi bật âm thanh thì clip âm thanh sẽ được khởi tạo để sẵn sàng phát.
+ Phương thức loadImage() với 3 tham số truyền vào (s,w,h): trả về hình ảnh được lấy từ đường dẫn s và được ép kích thước sang (w,h).
+ Phương thức playSound() dùng để khởi tạo đối tượng clip để phát âm thanh với tham số truyền vào là chuỗi ký tự thể hiện đường dẫn đến file.
+ Các button trong class MaiMenu đều được cài đặt sự kiện (actionListener)
Phương thức actionPerformed() xử lý sự kiện trên các button Đối với button Play, khi người chơi nhấp vào sẽ khởi tạo đối tượng của lớp Creator và chương trình chuyển sang phần sắp xếp tàu chiến; còn với button HighScore, đối tượng của lớp HighScore sẽ được khởi tạo để hiển thị bảng xếp hạng.
HighScore được khởi tạo và chương trình chuyển sang màn hình hiển thị lịch sử điểm cao Người dùng có thể bật/tắt âm thanh bằng nút sound, chọn chế độ khó/dễ bằng nút gameMode, và nhấn nút gameRule để hiển thị hoặc ẩn label showRules; khi nhấn lần đầu, label showRules được thiết lập là visible và nhấn lần nữa sẽ bị xóa bỏ Cuối cùng, nút Exit cho phép thoát khỏi chương trình.
Lớp HighScore có phương thức khởi tạo với 3 tham số truyền vào là w, h và playSound, được dùng để thêm frame cho giao diện hiển thị điểm số và hiển thị hai nút chức năng chính là Reset (xóa lịch sử điểm cao) và Back (quay về menu chính), giúp người dùng dễ dàng quản lý bảng xếp hạng và điều hướng trong ứng dụng.
The resetHighScore() method resets all values in the high.txt file to zero, providing a clean slate for score tracking, while the showScore() method reads high.txt and displays the score history of the top five scores, offering quick visibility into the highest achievements Together, these functions provide a simple file-based approach to managing game scores, with resetHighScore clearing the record and showScore surfacing the five best results.
+ Phương thức loadImage(): với 3 tham số truyền vào (s,w,h): trả về hình ảnh được lấy từ đường dẫn s và được ép kích thước sang (w,h).
+ Phương thức playSound() dùng để khởi tạo đối tượng clip để phát âm thanh với tham số truyền vào là chuỗi ký tự thể hiện đường dẫn đến file.
Lớp Creactor kế thừa lớp JLabel, có chức năng hiển thị tàu và hiển thị hình ảnh bản đồ để người chơi có thể xếp tàu lên đó.
Trong giao diện người dùng, một JFrame (frame) được dùng để chứa các thành phần hiển thị trên màn hình Các Label chính gồm shipContainer để chứa hình ảnh của tàu và map để làm bản đồ hiển thị vị trí tàu Các button bao gồm back (quay trở lại màn hình menu của lớp MainMenu), auto (tự động sắp xếp tàu trên bản đồ theo thuật toán được cài sẵn) và ready (chuyển sang màn hình PlayGame khi người chơi đã sắp xếp xong các tàu lên map).
THUẬT TOÁN SỬ DỤNG
Công nghệ sử dụng
Để giải quyết bài toán về giao diện đồ họa, nhóm sử dụng công nghệ Java Swing và Java AWT
Các thuật toán đã sử dụng
3.2.1 Thuật toán sắp xếp tàu vào bản đồ
Khi người chơi nhấn nút Play từ menu, họ được chuyển tới màn hình sắp xếp các con tàu vào từng vị trí trên bản đồ Ở màn hình này, mảng boolean M[][] được khởi tạo với các giá trị ban đầu là false, đánh dấu mọi ô trên lưới là trống và sẵn sàng cho quá trình đặt tàu.
Trong trò chơi, khi người chơi giữ chuột vào 1 con tàu để chuẩn bị kéo thả, phương thức mousePressed được gọi; tại đây xStart và yStart nhận giá trị tọa độ của con tàu (tọa độ của điểm góc trên bên trái của tàu), trong khi X và Y nhận giá trị là tọa độ của chuột Khi người chơi kéo con tàu trên bản đồ, phương thức MouseDragged được gọi và hình ảnh con tàu sẽ di chuyển theo chuột.
Trong trò chơi, khi người chơi kéo tàu ra và nhấn chuột phải đồng thời, hai phương thức mouseClicked và mousePressed được gọi, và tàu sẽ xoay theo mỗi lần nhấn chuột phải.
Khi người chơi thả chuột, phương thức MouseReleased sẽ kiểm tra xem tại vị trí thả chuột con tàu có nằm trong vùng bản đồ hay không Nếu vị trí đó không nằm trong bản đồ, con tàu sẽ được di chuyển về vị trí xStart và yStart, hai biến đã được tính toán từ trước để xác định điểm khởi đầu của tàu.
Trong trường hợp người dùng nhấn chuột (MousePressed), nếu con tàu nằm trong vùng bản đồ, chương trình sẽ kiểm tra xem tại vị trí mới đã có tàu khác chiếm giữ hay chưa Nếu có tàu khác ở đó, tàu hiện tại sẽ được di chuyển về xStart và yStart Nếu không có tàu nào ở vị trí mới, tàu sẽ được chuyển đến tọa độ mới và mảng M sẽ được cập nhật lại để phản ánh sự di chuyển.
3.2.2 Thuật toán chơi game chế độ dễ Ở chế độ dễ, mỗi lượt máy bắn sẽ là 1 ô bất kỳ trên bản đồ nhờ vào phương thức hitRandom và biến random rd trong phương thức.
3.2.3 Thuật toán chơi game chế độ khó Ở chế độ khó, chương trình sử dụng 1 hàng đợi Q để lưu tọa độ các ô trên bản đồ, xuất phát từ Q rỗng.
Khi đến lượt máy bắn, chương trình kiểm tra hàng đợi Q rỗng hay không:
Khi Q rỗng, thuật toán sẽ dùng biến ngẫu nhiên để bắn một ô bất kỳ trên bản đồ Nếu ô được bắn chứa tàu, gọi là ô (i,j), thì bốn ô liền kề (i+1,j), (i-1,j), (i,j+1) và (i,j-1) sẽ được thêm vào hàng đợi để chờ lượt bắn tiếp theo Cách làm này giúp mở rộng tìm kiếm từ các ô bị đánh trúng và tối ưu hóa chiến lược tấn công trên bản đồ trong các lượt chơi kế tiếp.
Khi hàng đợi Q còn phần tử, chương trình lấy ô ở đầu hàng để bắn Nếu ô này có tàu, được coi là ô (i,j), thì bốn ô liền kề là (i+1,j), (i-1,j), (i,j+1) và (i,j-1) sẽ được thêm vào hàng đợi để chờ lượt bắn tiếp theo.
XÂY DỰNG CHƯƠNG TRÌNH MINH HỌA
Kết quả chương trình minh họa
Chương trình đã thực hiện được những chức năng chính sau:
+ Cho phép người chơi lựa chọn tàu chiến, sắp xếp đội hình (mỗi loại tàu chiến có các kích thước, hướng khác nhau)
+ Đánh dấu tọa độ bắn trật, bắn trúng của mỗi lượt chơi
+ Thống kê số lần đã bắn, bắn trúng hay trượt, vị trí đã bắn
+ Lưu lại điểm số của người chơi
+ Xây dựng thuật toán cho máy chơi ở chế độ khó và dễ
+ Chơi với máy, xem lịch sử điểm cao.
+ Cấu hình game: tắt bật âm thanh, reset điểm cao
Giao diện chương trình
1 Giao diện khi bắt đầu khởi chạy game
2 Giao diện xem lịch sử điểm cao
3 Giao diện sắp xếp tàu lên bản đồ
5 Giao diện kết thúc game
Kiểm thử các chức năng
Các chức năng chính cần kiểm thử:
+ Cho phép người chơi sắp xếp đội hình (mỗi loại tàu chiến có các kích thước khác nhau, có thể thay đổi hướng của tàu)
+ Lưu lại điểm số của người chơi
+ Xem lịch sử điểm cao, reset điểm cao
4.3.1 Kiểm thử cho chức năng 1
Chức năng: cho phép người chơi lựa chọn, sắp xếp, xoay tàu chiến.
Mỗi loại tàu chiến có giới hạn cố định là 5 tàu, tương ứng với 5 kích thước khác nhau Độ dài của tàu được biểu thị bằng số ô trên bản đồ: tàu dài 1 ô, 2 ô, 3 ô, 4 ô hoặc 5 ô.
Kết quả kiểm thử sắp xếp tàu chiến
STT input Exception Kết quả
1 Các tàu chưa nằm hết trong map Xử lý: không cho người chơi bấm vào nút ready OK
2 Các tàu đã nằm trên map Xử lý: cho phép người chơi bấm nút ready OK
4.3.2 Kiểm thử cho chức năng 2
Chức năng: Lưu lại điểm số, xem lịch sử điểm số, reset điểm cao
STT input Exception Kết quả
1 File highscore.txt không tồn tại Xử lý: tạo mới file highscore.txt OK
2 File highscore.txt được nhập thành công Không xử lý OK
4.3.3 Kiểm thử cho chức năng 3
Chức năng: bật tắt âm thanh
STT input Exception Kết quả
1 File sound.wav không tồn tại Xử lý: bỏ qua âm thanh OK
2 File sound.wav đã tồn tại Không xử lý OK
4.3.4 Kiểm thử cho chức năng 4
Chức năng: xem hướng dẫn chơi
STT input Exception Kết quả
1 File gamerule.txt không tồn tại Xử lí: không hiện hướng dẫn chơi OK
2 File gamerule.txt được tìm thấy Không xử lí OK
Chương trình chạy ổn định, ít lỗi logic xảy ra Nếu có lỗi xảy ra thì đa phần là do các file input bị thiếu hoặc lỗi.
KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
Chương trình đã hoàn thành được những yêu cầu cơ bản của bài toán. Ưu điểm:
+ Nhẹ, tốn ít tài nguyên
+ Một số hình ảnh trong game chưa thực sự đẹp
+ Các lớp trong chương trình còn sử dụng nhiều thuộc tính
Hướng phát triền cho đề tài:
+ Giảm thiểu các thuộc tính cho các lớp bằng các biến cục bộ
+ Tìm kiếm thêm hình ảnh để giao diện game trau chuốt hơn
+ Thêm hướng dẫn chơi để người chơi dễ hiểu
Dù vẫn còn một số thiếu sót, những gì thu được từ bài tập lớn lần này mang lại những bài học quý giá và ý nghĩa Bằng sự nỗ lực và trải nghiệm thực tế, chúng em nhận thấy tiến bộ rõ rệt, từ đó tự tin hơn để tiếp tục theo đuổi đam mê lập trình Thành quả này không chỉ củng cố niềm yêu thích với lập trình mà còn tiếp thêm động lực để hoàn thiện kỹ năng và thực hiện những dự án lớn trong tương lai.
Chúng em rất mong nhận được những đánh giá của thầy.
Chúng em xin chân thành cảm ơn!