Sweep
一:團隊組成
團隊名稱:Sweep
團隊成員介紹:陳玉婷,彭佳妮,羅梅麗
任務分配:
陳玉婷:文件管理,及掃雷游戲算法實現,畫UML圖
彭佳妮:GUI登陸界面設置,用戶密碼驗證及其監聽,寫博客
羅梅麗:GUI登陸界面設置,寫博客
| 成員 | 博客鏈接 |
| 陳玉婷(組長) | https://www.cnblogs.com/chenyutin/p/10279348.html
|
| 彭佳妮 | https://www.cnblogs.com/pengjiani/p/10280987.html |
| 羅梅麗 | https://www.cnblogs.com/luomeili/p/10281816.html |
二:項目Git地址及提交記錄
Git地址
https://gitee.com/pengjiani/mine_clearance
提交記錄



三:項目簡介
游戲介紹:
掃雷游戲介紹:
《掃雷》是一款大眾類的益智小游戲。游戲目標是在最短的時間內根據點擊格子出現的數字找出所有非雷格子,同時避免踩雷,踩到一個雷即全盤皆輸。
游戲設定:
游戲區包括雷區,確定大小的矩形雷區中隨機布置一定數量的地雷(初級為9*9個方塊9個雷,中級為14*14個方塊14個雷,高級為16*16個方塊16個雷,玩家需要盡快找出雷區中的所有不是地雷的方塊,而不許踩到地雷。
項目功能架構圖與主要功能流程圖
功能流程圖


功能構架圖

組織形式

項目運行演示

優秀設計部分
可以保存游戲進度,增加游戲的靈活性和用戶體驗
保存游戲進度

再次登陸時進入上一次游戲

項目關鍵代碼
界面顯示模塊
//登陸界面設置 setSize(496, 557); setLayout(new GridLayout(2, 1)); // JMenuBar bar=new JMenuBar(); HomePanel panelN = new HomePanel("2018-01-10_12-55-41.gif"); HomePanel panelS = new HomePanel("ApplicationFrameHost_2018-01-10_13-37-17.png"); panelN.setLayout(new FlowLayout()); JButton button=new JButton(); button.setIcon(new ImageIcon("ApplicationFrameHost_2018-01-10_13-39-56.png")); //button.setOpaque(false); //設置控件透明 button.setBorder(null); //設置邊框 button.setContentAreaFilled(false); //設置控件透明 button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { System.exit(0); } }); //鍵盤監聽 KeyListener key_Listener = new KeyListener() { public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e){} public void keyPressed(KeyEvent e){ if(e.getKeyChar() == KeyEvent.VK_ENTER ) { String name = usenameField.getText(); String word = new String(passwordField.getPassword()); if(judge(name,word) == 0) JOptionPane.showMessageDialog(null, "用戶名不存在!"); else if(judge(name,word) == -1) JOptionPane.showMessageDialog(null, "密碼錯誤!"); else { Selection selection=new Selection(file); MFrame.this.dispose(); } try { file.setFileName(usenameField.getText()); // Selection selection=new Selection(file); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } } }; passwordField.addKeyListener(key_Listener);
算法模塊
我們的掃雷由n x m 的方格區域構成,當我們點擊其中一個方塊的時候,如果它不是雷,它就應當以數字的形式表示出在它外圈的一圈內包含有多少個雷,這個數字的范圍是1到8,在它不是雷的前提下,如果它周圍也沒有雷的話,那我們點擊的方塊在下一秒應當展開當前的一片無雷的區域,以數字作為邊界,該邊界指出外圈的雷的數目,我們的做法是,以二維數組的形式定義一片區域,每二維數組上的每一個數字映射着我們雷區的每一塊方格,然后就是該二維數組的數字的范圍,我們取整型數字的范圍為0到9,用9來表示雷,用0到8來表示外圍雷的數目,我們這里的0在 后是不用來顯示在方塊上的,我們判斷到方塊下面的數字是0的話我們會讓雷區展開一片空白區域。
也就是說,我們剛開始初始化了一個二維數組map,來映射一片雷區,其中的整型數字范圍為0到9,用9來表示雷。
所以剛開始的代碼,將二維數組初始化為0,接下來按行隨機和列隨機的方式隨機布下指定數目的雷的數量,這樣,我們 開始的而且也是掃雷中 實際的“雷區”(map)也就生成了。
但 終要實現用戶交互界面,所以需要將我們的map映射到frame上,並能實現點擊交互。我們這里的做法是,使用按鈕,覺得使用按鈕可以不必再去鼠標點擊的區域的具體坐標,直接使用按鈕監聽器來實現對點擊位置的具體把控。
所以我們在交互界面,frame上,我們初始化了JButton數組,然后使用了gridlayout的網格布局將按鈕布置上去,剛開始的按鈕的外觀慘不忍睹,后來才采用了圖片的形式來替代默認的按鈕外觀。這些是外在,內在我們還有很多需要考慮的地方。先記住我們的初始化雷區map是0到9的二維數組。
比如,我們剛開始需要為用戶提供一個初始界面,就是都沒有被動過的按鈕,當用戶點擊的時候,需要展開區域,還是顯示數字,還是顯示雷,還是標記此位置為雷,每一個按鈕的“狀態”即外觀都是不一樣的,而這些“狀態”的改變與我們的map上面的數字不能直接形成一一映射的關系,也就是說,我們狀態需要改變,但是我們的map是我們基本的雷區,是不能被改變的,而且0到9的范圍有10種狀態選擇,但我們的交互界面需要的狀態變化有13種,所以為了解決這種問題,我們引入了一層隱藏層,來表示我們的frame上面的每一塊方塊的狀態變化,我們為隱藏層命名為hiddenmap,同樣為我們的int型以便於儲存多“狀態”。

部分代碼:
public void findZero(int i, int j) { if (hiddenmap[i][j] != 0) { if (map[i][j] == 0) { hiddenmap[i][j] = 0; if (i == 0) { if (j == 0) { if (map[i][j + 1] != 0 && map[i][j + 1] != 9) hiddenmap[i][j + 1] = map[i][j + 1]; if (map[i + 1][j] != 0 && map[i + 1][j] != 9) hiddenmap[i + 1][j] = map[i + 1][j]; } else if (j == length - 1) { if (map[i][j - 1] != 0 && map[i][j - 1] != 9) hiddenmap[i][j - 1] = map[i][j - 1]; if (map[i + 1][j] != 0 && map[i + 1][j] != 9) hiddenmap[i + 1][j] = map[i + 1][j]; } else { if (map[i][j - 1] != 0 && map[i][j - 1] != 9) hiddenmap[i][j - 1] = map[i][j - 1]; if (map[i + 1][j] != 0 && map[i + 1][j] != 9) hiddenmap[i + 1][j] = map[i + 1][j]; if (map[i][j + 1] != 0 && map[i][j + 1] != 9) hiddenmap[i][j + 1] = map[i][j + 1]; } } if (i == width - 1) { if (j == 0) { if (map[i][j + 1] != 0 && map[i][j + 1] != 9) hiddenmap[i][j + 1] = map[i][j + 1]; if (map[i - 1][j] != 0 && map[i - 1][j] != 9) hiddenmap[i - 1][j] = map[i - 1][j]; } else if (j == length - 1) { if (map[i - 1][j] != 0 && map[i - 1][j] != 9) hiddenmap[i - 1][j] = map[i - 1][j]; if (map[i][j - 1] != 0 && map[i][j - 1] != 9) hiddenmap[i][j - 1] = map[i][j - 1]; } else { if (map[i][j + 1] != 0 && map[i][j + 1] != 9) hiddenmap[i][j + 1] = map[i][j + 1]; if (map[i - 1][j] != 0 && map[i - 1][j] != 9) hiddenmap[i - 1][j] = map[i - 1][j]; if (map[i][j - 1] != 0 && map[i][j - 1] != 9) hiddenmap[i][j - 1] = map[i][j - 1]; } } if (j == 0) { if (i != 0 && i != width - 1) { if (map[i - 1][j] != 0 && map[i - 1][j] != 9) hiddenmap[i - 1][j] = map[i - 1][j]; if (map[i + 1][j] != 0 && map[i + 1][j] != 9) hiddenmap[i + 1][j] = map[i + 1][j]; if (map[i][j + 1] != 0 && map[i][j + 1] != 9) hiddenmap[i][j + 1] = map[i][j + 1]; } } if (j == length - 1) { if (i != 0 && i != width - 1) { if (map[i - 1][j] != 0 && map[i - 1][j] != 9) hiddenmap[i - 1][j] = map[i - 1][j]; if (map[i + 1][j] != 0 && map[i + 1][j] != 9) hiddenmap[i + 1][j] = map[i + 1][j]; if (map[i][j - 1] != 0 && map[i][j - 1] != 9) hiddenmap[i][j - 1] = map[i][j - 1]; } } if (i != 0 && i != width - 1 && j != 0 && j != length - 1) { if (map[i][j + 1] != 0 && map[i][j + 1] != 9) hiddenmap[i][j + 1] = map[i][j + 1]; if (map[i + 1][j] != 0 && map[i + 1][j] != 9) hiddenmap[i + 1][j] = map[i + 1][j]; if (map[i][j - 1] != 0 && map[i][j - 1] != 9) hiddenmap[i][j - 1] = map[i][j - 1]; if (map[i - 1][j] != 0 && map[i - 1][j] != 9) hiddenmap[i - 1][j] = map[i - 1][j]; } if (j >= 1) findZero(i, j - 1); if (i >= 1) findZero(i - 1, j); if (j <= getLength() - 2) findZero(i, j + 1); if (i <= getWidth() - 2) findZero(i + 1, j); } } }
ObjectInputStream readFile; if (file.isNewOne() == false) { try { readFile = new ObjectInputStream(new FileInputStream(file.getFileName())); this.minefield = (Minefield) readFile.readObject(); readFile.close(); if (minefield.isBoom() == true) { boom.play(); upset.play(); } else { playGame.play(); } } catch (FileNotFoundException e) { //不存在上局時,自動生成一局 this.minefield = new Minefield(file.getWidth(), file.getLength(), file.getLambnumber()); playGame.play(); // JOptionPane.showMessageDialog(null, "您還未開始游戲,不存在上局哦!"); // e.printStackTrace(); } catch (IOException e) { // e.printStackTrace(); } }
四:代碼掃描結果及改正


改正步驟
第一種錯誤:缺少覆蓋標志@Override


第二種:缺少大括號


待改進
不足:沒有設置計時器和剩余雷的個數。按鈕無法改變大小,所以限制了游戲界面無法改變大小。
改良:設置一下計時器和剩余雷的個數,然后將按鈕設置成能隨着框的改變個改變大小,這就比較可以了。
五:UML圖

六:參考文獻

