一、題目簡介
1、計算機能對棋局進行分析、判斷。根據棋局狀態來確定機器方的下棋行為。
2、計算機能根據棋局狀態實時的判斷對弈雙方的勝負。
3、控制雙方交替下棋。
4、友好的介面呈現。
二、結對分工及過程
結對 劉永政(學號後四位:1139) 張斌(學號後四位:1136)
組員各自的優缺點:
1.劉永政: 程式碼的編寫和程式碼規範。
2.張斌:程式的分析和程式的測試及測試程式碼的編寫
三、結對程式設計優缺點:
優點:
1.結對程式設計時間緊密,在一定程度上可以督促雙方學習,提高效率。
2.Coder在coding過程中會遇到一些細小的問題,而reviewer可以及時指出錯誤,並給予解決方案進行討論。
3.遇到問題時,兩個人一起討論,並補充對方沒有想到的地方,是完善程式最好的方式。
缺點:
在程式設計過程中,很長時間是coder在coding的過程中想思路,大概這也是每個程式設計師的特點,而這個時候reviewer就會長時間遇到空檔期。
四、程式碼地址
https://github.com/LINKVK/test/tree/master
原始碼:
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.event.*; | |
import java.net.URL; | |
@SuppressWarnings("serial") | |
public class ChessMap extends JFrame { | |
private ImageIcon map; //棋盤背景點陣圖 | |
private ImageIcon blackchess; //黑子點陣圖 | |
private ImageIcon whitechess; //白子點陣圖 | |
private ChessPanel cp; //棋盤 | |
private JPanel east; | |
private JPanel west; | |
private static final int FINAL_WIDTH = 450; | |
private static final int FINAL_HEIGHT = 500; | |
//以下為下拉選單 | |
private JMenuBar menubar; | |
private JMenu[] menu={new JMenu("開始"),new JMenu("設定"),new JMenu("幫助")}; | |
private JMenuItem[] menuitem1={new JMenuItem("重新開始"),new JMenuItem("悔棋"),new JMenuItem("退出")}; | |
private JMenuItem[] menuitem2={new JMenuItem("禁手選擇"),new JMenuItem("人機對戰"),new JMenuItem("雙人對戰")}; | |
private JMenuItem[] menuitem3={new JMenuItem("規則"),new JMenuItem("關於")}; | |
private boolean haveai=true; //人與人下還是人與電腦下,true與電腦下 | |
Mouseclicked mouseclicked=new Mouseclicked(); | |
MouseMoved mousemoved=new MouseMoved(); | |
Menuitemclicked menuclicked=new Menuitemclicked(); | |
//建構函式 | |
public ChessMap(){ | |
//改變系統預設字型 | |
Font font = new Font("Dialog", Font.PLAIN, 12); | |
java.util.Enumeration keys = UIManager.getDefaults().keys(); | |
while (keys.hasMoreElements()) { | |
Object key = keys.nextElement(); | |
Object value = UIManager.get(key); | |
if (value instanceof javax.swing.plaf.FontUIResource) { | |
UIManager.put(key, font); | |
} | |
} | |
setTitle("五子棋 "); | |
setSize(FINAL_WIDTH,FINAL_HEIGHT); | |
setResizable(false); | |
init(); | |
setLocation(Toolkit.getDefaultToolkit().getScreenSize().width / 2 | |
- FINAL_WIDTH / 2, Toolkit.getDefaultToolkit() | |
.getScreenSize().height | |
/ 2 - FINAL_HEIGHT / 2); | |
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
cp.reset(); | |
setVisible(true); | |
} | |
//初始化與預設值 | |
public void init() | |
{ | |
map=new ImageIcon(getClass().getResource("bg.jpg")); | |
blackchess=new ImageIcon(getClass().getResource("blackchess.gif")); | |
whitechess=new ImageIcon(getClass().getResource("whitechess.gif")); | |
cp=new ChessPanel(map,blackchess,whitechess); | |
menubar=new JMenuBar(); | |
menuitem1[0].setActionCommand("Restart"); | |
menuitem1[1].setActionCommand("Rollback"); | |
menuitem1[2].setActionCommand("Exit"); | |
menuitem2[0].setActionCommand("Forbid"); | |
menuitem2[1].setActionCommand("Robot"); | |
menuitem2[2].setActionCommand("Human"); | |
menuitem3[0].setActionCommand("Rule"); | |
menuitem3[1].setActionCommand("About"); | |
for(int i=0;i<3;i++) | |
menu[0].add(menuitem1[i]); | |
for(int i=0;i<3;i++) | |
menu[1].add(menuitem2[i]); | |
for(int i=0;i<2;i++) | |
menu[2].add(menuitem3[i]); | |
for(int i=0;i<3;i++) | |
menubar.add(menu[i]); | |
Container p = getContentPane(); | |
setJMenuBar(menubar); | |
east = new JPanel(); | |
west = new JPanel(); | |
p.add(east, "East"); | |
p.add(west, "West"); | |
p.add(cp, "Center"); | |
cp.addMouseListener(mouseclicked); | |
cp.addMouseMotionListener(mousemoved); | |
menuitem1[0].addActionListener(menuclicked); | |
menuitem1[1].addActionListener(menuclicked); | |
menuitem1[2].addActionListener(menuclicked); | |
menuitem2[0].addActionListener(menuclicked); | |
menuitem2[1].addActionListener(menuclicked); | |
menuitem2[2].addActionListener(menuclicked); | |
menuitem3[0].addActionListener(menuclicked); | |
menuitem3[1].addActionListener(menuclicked); | |
} | |
class Mouseclicked extends MouseAdapter //判斷滑鼠左擊並通知棋盤和電腦 | |
{ | |
public void mouseClicked(MouseEvent e) | |
{ | |
if(cp.win==false){ | |
if(haveai){ //和電腦博弈 | |
Point p1=new Point(); | |
p1=cp.getPoint(e.getX(),e.getY()); | |
int x=p1.x; | |
int y=p1.y; | |
// 如果該位置已經放置棋子 | |
System.out.println("x="+x+",y="+y); | |
if (cp.isChessOn[x][y] != 2) | |
return; | |
// 玩家為黑棋,考慮禁手 | |
if( cp.able_flag && cp.bw == 0) { | |
int type = cp.getType(x,y,cp.bw); | |
String str = null; | |
switch(type){ | |
case 20: | |
str = "黑長連禁手!請選擇其它位置下棋!"; | |
break; | |
case 21: | |
str = "黑四四禁手!請選擇其它位置下棋!"; | |
break; | |
case 22: | |
str = "黑三三禁手!請選擇其它位置下棋!"; | |
break; | |
default : break; | |
} | |
if(str != null) { | |
JOptionPane.showMessageDialog(null,str); | |
return; | |
} | |
} | |
boolean flag=cp.haveWin(x, y, cp.bw); | |
cp.update( x, y ); | |
cp.putVoice(); //落子聲音 | |
// 第一步棋,需初始化設定邊界值 | |
if( cp.chess_num == 1){ | |
if(x-1>=0) | |
cp.x_min = x-1; | |
if(x-1<=15) | |
cp.x_max = x+1; | |
if(y-1>=0) | |
cp.y_min = y-1; | |
if(y-1<=15) | |
cp.y_max = y+1; | |
} | |
else | |
cp.resetMaxMin(x,y); | |
if (flag) { | |
cp.wined(1 - cp.bw); | |
return; | |
} | |
cp.putOne(cp.bw); | |
}else{ //和人博弈 | |
Point p1=new Point(); | |
p1=cp.getPoint(e.getX(),e.getY()); | |
int x=p1.x; | |
int y=p1.y; | |
// 如果該位置已經放置棋子 | |
System.out.println("x="+x+",y="+y); | |
if (cp.isChessOn[x][y] != 2) | |
return; | |
// 玩家為黑棋,考慮禁手 | |
if( cp.able_flag && cp.bw == 0) { | |
int type = cp.getType(x,y,cp.bw); | |
String str = null; | |
switch(type){ | |
case 20: | |
str = "黑長連禁手!請選擇其它位置下棋!"; | |
break; | |
case 21: | |
str = "黑四四禁手!請選擇其它位置下棋!"; | |
break; | |
case 22: | |
str = "黑三三禁手!請選擇其它位置下棋!"; | |
break; | |
default : break; | |
} | |
if(str != null) { | |
JOptionPane.showMessageDialog(null,str); | |
return; | |
} | |
} | |
boolean flag=cp.haveWin(x, y, cp.bw); | |
cp.update( x, y ); | |
cp.putVoice(); //落子聲音 | |
cp.repaint(); | |
// 第一步棋,需初始化設定邊界值 | |
if( cp.chess_num == 1){ | |
if(x-1>=0) | |
cp.x_min = x-1; | |
if(x-1<=15) | |
cp.x_max = x+1; | |
if(y-1>=0) | |
cp.y_min = y-1; | |
if(y-1<=15) | |
cp.y_max = y+1; | |
} | |
else | |
cp.resetMaxMin(x,y); | |
if (flag) { | |
cp.wined(1 - cp.bw); | |
return; | |
} | |
} | |
} | |
} | |
} | |
class MouseMoved implements MouseMotionListener //除錯用,獲得滑鼠位置 | |
{ | |
public void mouseMoved(MouseEvent e) | |
{ | |
cp.showMousePos(e.getPoint()); | |
} | |
public void mouseDragged(MouseEvent e) | |
{} | |
} | |
class Menuitemclicked implements ActionListener //選單訊息處理 | |
{ | |
public void actionPerformed(ActionEvent e) | |
{ | |
JMenuItem target = (JMenuItem)e.getSource(); | |
String actionCommand = target.getActionCommand(); | |
if(actionCommand.equals("Restart")){ //重開一局 | |
cp.reset(); | |
if(cp.sbw==cp.WHITE_ONE) | |
cp.update(7, 7); | |
//player=cp.BLACK_ONE; | |
} | |
if(actionCommand.equals("Rollback")){ //悔棋 | |
if(cp.win) { | |
JOptionPane.showMessageDialog(null,"棋局已經結束,不能悔棋!請重新開始新的棋局!"); | |
return; | |
} | |
// 當前輪到玩家下棋,取消兩步 否則,取消一步 | |
if(cp.chess_num >= 2 && cp.bw == cp.sbw){ | |
cp.isChessOn[cp.pre[cp.chess_num-1][0]][cp.pre[cp.chess_num-1][1]] = 2; | |
cp.isChessOn[cp.pre[cp.chess_num-2][0]][cp.pre[cp.chess_num-2][1]] = 2; | |
cp.chess_num -= 2; | |
cp.repaint(); | |
} | |
else if(cp.chess_num >= 1 && cp.bw == 1-cp.sbw){ | |
cp.isChessOn[cp.pre[cp.chess_num-1][0]][cp.pre[cp.chess_num-1][1]] = 2; | |
cp.chess_num --; | |
cp.repaint(); | |
} | |
} | |
else if(actionCommand.equals("Exit")){ //退出 | |
System.exit(1); | |
} | |
else if(actionCommand.equals("Forbid")){ //禁手選擇 | |
Object[] options = { "無禁手", "有禁手" }; | |
int sel = JOptionPane.showOptionDialog( | |
null, "你的選擇:", "禁手選擇", | |
JOptionPane.DEFAULT_OPTION, | |
JOptionPane.QUESTION_MESSAGE, null, | |
options, options[0]); | |
if(sel==1){ | |
cp.able_flag=true; | |
System.out.println("有禁手"); | |
}else{ | |
cp.able_flag=false; | |
System.out.println("無禁手"); | |
} | |
} | |
else if(actionCommand.equals("Robot")){ //人機博弈 | |
haveai=true; | |
Object[] options = { "人類先手", "機器先手" }; | |
int sel = JOptionPane.showOptionDialog( | |
null, "你的選擇:", "先手選擇", | |
JOptionPane.DEFAULT_OPTION, | |
JOptionPane.QUESTION_MESSAGE, null, | |
options, options[0]); | |
if(sel==1){ //機器先手 | |
cp.sbw=cp.WHITE_ONE; | |
cp.update(7, 7); | |
System.out.println("機器先手"); | |
}else{ //人先手 | |
//player=cp.BLACK_ONE; | |
cp.sbw=cp.BLACK_ONE; | |
System.out.println("人先手"); | |
} | |
} | |
else if(actionCommand.equals("Human")){ //人人博弈 | |
haveai=false; | |
cp.setHumanhuman(true); | |
}else if(actionCommand.equals("Rule")){ //規則 | |
JOptionPane.showConfirmDialog(null, | |
"1、無禁手:" +"\n"+ | |
" 黑白雙方依次落子,任一方先在棋盤上形成連續的五個(含五個以上)棋子的一方為勝。" +"\n"+ | |
"2、有禁手:(走禁手就輸,禁手不能落子)" +"\n"+ | |
" 鑑於無禁手規則黑棋必勝,人們不斷採用一些方法限制黑棋先行的優勢,以平衡黑白雙方的形式。" +"\n"+ | |
" 於是針對黑棋的各種禁手逐漸形成。" +"\n"+ | |
" 禁手主要分為以下幾類:" +"\n"+ | |
" (1)黑長連禁手:連成六個以上連續相同的棋子。" +"\n"+ | |
" (2)黑三三禁手:兩個以上的活三。" + "\n"+ | |
" (3)黑四四禁手:兩個以上的四。" + "\n"+ | |
" 禁手是針對黑棋而言的,白棋沒有任何禁手。" ,"規則",JOptionPane.CLOSED_OPTION,JOptionPane.INFORMATION_MESSAGE); | |
} | |
else if(actionCommand.equals("About")){ //版權與幫助 | |
JOptionPane.showConfirmDialog(null,"團隊成員:\n" + | |
"張斌\n" + | |
"劉永政","關於",JOptionPane.CLOSED_OPTION,JOptionPane.INFORMATION_MESSAGE); | |
} | |
} | |
} | |
public static void main(String[] args) { | |
new ChessMap(); | |
} | |
} |
執行截圖
五、測試情況
六、心得
這是我的第一次結對程式設計,總體感覺是很坑爹且痛苦。感覺上我還是不太適應結對程式設計這種模式,我們前期閱讀程式碼時是分開進行的,我總感覺我和一個人一起閱讀程式碼時會看不下去(然而儘管是一個人閱讀的,我的閱讀過程還是很痛苦)。而且兩個人進度難免不一樣,不過好在並不是太耽誤,而且結隊的優點也是不可忽視的,結對程式設計是提高程式碼走查效率和質量的非常有效的手段。