import java.awt.*; import java.io.*; import java.awt.event.*; import java.util.*; class Start{//初期状態を表すクラス public static void Start(){ for(int j = 0 ; j < Board.CellNumber ; j++){ for(int k = 0 ; k < Board.CellNumber ; k++){ Board.state[Board.count][j][k]= Board.Empty ; } } Board.state[Board.count][3][3]=Board.White; Board.state[Board.count][4][3]=Board.Black; Board.state[Board.count][3][4]=Board.Black; Board.state[Board.count][4][4]=Board.White;//初期値 } } class Board{ public static final int BoardWidth=650,BoardHeight=600;//盤の縦横 public static final int CellWidth=60,CellHeight=60;//ますの縦横 public static final int CellNumber=8;//ますの数 public static final int White=-1,Empty=0, Black=1;//駒の色に対応する数字 public int Cellx,Celly;//ますめの位置 public static int count=0;//何手目のものか int il=0,ir=0,id=0,iu=0,iur=0,iru=0,idr=0,ird=0,ilu=0,iul=0,ild=0,idl=0;//それぞれの方向に調べる:rが右,lが左、uが上、dが下を表す int No=0;//コピーして良いかを示す int virtualcount; //そのときの状態を表す配列 public static int[][][] state = new int[61][8][8]; /** ここから各方向にひっくり返せるかどうかをチェックするメソッドが開始します。 まずcount回目の配列をcount+1回目のものにコピーし、一回もひっくり返さなかったら 再びcount回目のものを表示するようにしてます。 チェックの仕方としては、黒の番を考えると各方向に対してまず隣に白がないかを調べて、 白があったらさらにその隣を調べます。調べて行って黒があったらひっくり返す。という作業を行っているので 各方向と黒白の場合を全部調べているため膨大な量になってしまっています。 */ // // // 黒のチェック開始・・・・ // // void checkBlack(){ if (No==0){ virtualcount=count; for(int i=0; i<8;i++){ for(int j=0; j<8;j++){ state[count+1][i][j]=state[count][i][j]; } No=1; } }//count回目の状態をcount+1回目の状態にコピー //右方向 if (Cellx<=6-ir && state[virtualcount][Cellx+1+ir][Celly]==Black){//となりが黒だったら if (count==virtualcount && ir !=0){//まだひっくり返してなかったら count++;//一回進めて } for(int k=0 ; k <=ir ; k++){ state[count][Cellx+k][Celly]=1;//ひっくり返す } } else if (Cellx<=6-ir && state[virtualcount][Cellx+1+ir][Celly]==White){//となりが白だったら ir++; if(ir<=6)checkBlack();//もう一個となりを探索 } else if (Cellx<=6-ir && state[virtualcount][Cellx+1+ir][Celly]==Empty){ state[virtualcount][Cellx][Celly]=0; } // //以下、この作業を各方向に繰り返し // //左方向 if (Cellx>=il+1 && state[virtualcount][Cellx-il-1][Celly]==Black){ if (count==virtualcount && il!=0){ count++; } for(int k=0 ; k <=il ; k++){ state[count][Cellx-k][Celly]=1; } } else if (Cellx>=il+1 && state[virtualcount][Cellx-il-1][Celly]==White){ il++; if(il<=6)checkBlack(); } else if (Cellx>=il+1 && state[virtualcount][Cellx-il-1][Celly]==Empty){ state[virtualcount][Cellx][Celly]=0; } //上 if (Celly>=iu+1 && state[virtualcount][Cellx][Celly-iu-1]==Black){ if (count==virtualcount && iu!=0){ count++; } for(int k=0 ; k <=iu ; k++){ state[count][Cellx][Celly-k]=1; } } else if (Celly>=iu+1 && state[virtualcount][Cellx][Celly-iu-1]==White){ iu++; if(iu<=6)checkBlack(); } else if (Celly>=iu+1 && state[virtualcount][Cellx][Celly-iu-1]==Empty){ state[virtualcount][Cellx][Celly]=0; } //下方向 if (Celly<=6-id && state[virtualcount][Cellx][Celly+1+id]==Black){ if (count==virtualcount && id!=0){ count++; } for(int k=0 ; k <=id ; k++){ state[count][Cellx][Celly+k]=1; } } else if (Celly<=6-id && state[virtualcount][Cellx][Celly+1+id]==White){ id++; if(id<=6)checkBlack(); } else if (Celly<=6-id && state[virtualcount][Cellx][Celly+1+id]==Empty){ state[virtualcount][Cellx][Celly]=0; } //上右方向 if (Cellx<=6-iru && Celly>=iur+1 && state[virtualcount][Cellx+1+iru][Celly-iur-1]==Black){ if (count==virtualcount && iru!=0 && iur!=0){ count++; } for(int k=0 ; k <=iur ; k++){ state[count][Cellx+k][Celly-k]=1; } } else if (Cellx<=6-iru && Celly>=iur+1 && state[virtualcount][Cellx+1+iru][Celly-iur-1]==White){ iur++;iru++; if(iur<=6 && iru<=6)checkBlack(); } else if (Cellx<=6-iru && Celly>=iur+1 && state[virtualcount][Cellx+1+iru][Celly-iur-1]==Empty){ state[virtualcount][Cellx][Celly]=0; } //下右方向 if (Cellx<=6-ird && Celly<=6-idr && state[virtualcount][Cellx+1+ird][Celly+1+idr]==Black){ if (count==virtualcount && idr!=0 && ird!=0){ count++; } for(int k=0 ; k <=ird ; k++){ state[count][Cellx+k][Celly+k]=1; } } else if (Cellx<=6-ird && Celly<=6-idr && state[virtualcount][Cellx+1+ird][Celly+1+idr]==White){ idr++;ird++; if(idr<=6 && ird<=6)checkBlack(); } else if (Cellx<=6-ird && Celly<=6-idr && state[virtualcount][Cellx+1+ird][Celly+1+idr]==Empty){ state[virtualcount][Cellx][Celly]=0; } //下左方向 if (Cellx>=1+ild && Celly<=6-idl && state[virtualcount][Cellx-ild-1][Celly+1+idl]==Black){ if (count==virtualcount && idl!=0 && ild!=0){ count++; } for(int k=0 ; k <=ild ; k++){ state[count][Cellx-k][Celly+k]=1; } } else if (Cellx>=1+ild && Celly<=6-idl && state[virtualcount][Cellx-ild-1][Celly+1+idl]==White){ idl++;ild++; if(idl<=6 && ild<=6)checkBlack(); } else if (Cellx>=1+ild && Celly<=6-idl && state[virtualcount][Cellx-ild-1][Celly+1+idl]==Empty){ state[virtualcount][Cellx][Celly]=0; } //上左方向 if (Cellx>=1+ilu && Celly>=iul+1 && state[virtualcount][Cellx-ilu-1][Celly-iul-1]==Black){ if (count==virtualcount && ilu!=0 && iul!=0){ count++; } for(int k=0 ; k <=ilu ; k++){ state[count][Cellx-k][Celly-k]=1; } } else if (Cellx>=1+ilu && Celly>=iul+1 && state[virtualcount][Cellx-ilu-1][Celly-1-iul]==White){ iul++;ilu++; if(iul<=6 && ilu<=6)checkBlack(); } else if (Cellx>=1+ilu && Celly>=iul+1 && state[virtualcount][Cellx-ilu-1][Celly-1-iul]==Empty){ state[virtualcount][Cellx][Celly]=0; } if (virtualcount==count)state[count][Cellx][Celly]=0; else state[count][Cellx][Celly]=1; } // // // 白のチェック開始・・・・ // // void checkWhite(){ if (No==0){ virtualcount=count; for(int i=0; i<8;i++){ for(int j=0; j<8;j++){ state[count+1][i][j]=state[count][i][j]; } } No=1; }//count回目の状態をcount+1回目の状態にコピー //右方向 if (Cellx<=6-ir && state[virtualcount][Cellx+1+ir][Celly]==White){//となりが白だったら if (count==virtualcount && ir!=0){//まだ一個もひっくり返してなかったら count++;//一回文進めて } for(int k=0 ; k <=ir ; k++){ state[count][Cellx+k][Celly]=-1;//ひっくり返しを実行 } } else if (Cellx<=6-ir && state[virtualcount][Cellx+1+ir][Celly]==Black){//となりが黒だったら ir++; if(ir<=6)checkWhite();//端っこじゃなかったらもう一個となりを探索 } else if (Cellx<=6-ir && state[virtualcount][Cellx+1+ir][Celly]==Empty){ state[virtualcount][Cellx][Celly]=0; } //以下この作業を各方向に繰り返し // // //左方向 if (Cellx>=il+1 && state[virtualcount][Cellx-il-1][Celly]==White){ if (count==virtualcount && il!=0){ count++; } for(int k=0 ; k <=il ; k++){ state[count][Cellx-k][Celly]=-1; } } else if (Cellx>=il+1 && state[virtualcount][Cellx-il-1][Celly]==Black){ il++; if(il<=6)checkWhite(); } else if (Cellx>=il+1 && state[virtualcount][Cellx-il-1][Celly]==Empty){ state[virtualcount][Cellx][Celly]=0; } //上 if (Celly>=iu+1 && state[virtualcount][Cellx][Celly-iu-1]==White){ if (count==virtualcount && iu!=0){ count++; } for(int k=0 ; k <=iu ; k++){ state[count][Cellx][Celly-k]=-1; } } else if (Celly>=iu+1 && state[virtualcount][Cellx][Celly-iu-1]==Black){ iu++; if(iu<=6)checkWhite(); } else if (Celly>=iu+1 && state[virtualcount][Cellx][Celly-iu-1]==Empty){ state[virtualcount][Cellx][Celly]=0; } //下方向 if (Celly<=6-id && state[virtualcount][Cellx][Celly+1+id]==White){ if (count==virtualcount && id!=0){ count++; } for(int k=0 ; k <=id ; k++){ state[count][Cellx][Celly+k]=-1; } } else if (Celly<=6-id && state[virtualcount][Cellx][Celly+1+id]==Black){ id++; if(id<=6)checkWhite(); } else if (Celly<=6-id && state[virtualcount][Cellx][Celly+1+id]==Empty){ state[virtualcount][Cellx][Celly]=0; } //上右方向 if (Cellx<=6-iru && Celly>=iur+1 && state[virtualcount][Cellx+1+iru][Celly-iur-1]==White){ if (count==virtualcount && iur!=0 && iru!=0){ count++; } for(int k=0 ; k <=iur ; k++){ state[count][Cellx+k][Celly-k]=-1; } } else if (Cellx<=6-iru && Celly>=iur+1 && state[virtualcount][Cellx+1+iru][Celly-iur-1]==Black){ iur++;iru++; if(iur<=6 && iru<=6)checkWhite(); } else if (Cellx<=6-iru && Celly>=iur+1 && state[virtualcount][Cellx+1+iru][Celly-iur-1]==Empty){ state[virtualcount][Cellx][Celly]=0; } //下右方向 if (Cellx<=6-ird && Celly<=6-idr && state[virtualcount][Cellx+1+ird][Celly+1+idr]==White){ if (count==virtualcount && idr!=0 && ird!=0){ count++; } for(int k=0 ; k <=ird ; k++){ state[count][Cellx+k][Celly+k]=-1; } } else if (Cellx<=6-ird && Celly<=6-idr && state[virtualcount][Cellx+1+ird][Celly+1+idr]==Black){ idr++;ird++; if(idr<=6 && ird<=6)checkWhite(); } else if (Cellx<=6-ird && Celly<=6-idr && state[virtualcount][Cellx+1+ird][Celly+1+idr]==Empty){ state[virtualcount][Cellx][Celly]=0; } //下左方向 if (Cellx>=1+ild && Celly<=6-idl && state[virtualcount][Cellx-ild-1][Celly+1+idl]==White){ if (count==virtualcount && idl!=0 && ild!=0){ count++; } for(int k=0 ; k <=ild ; k++){ state[count][Cellx-k][Celly+k]=-1; } } else if (Cellx>=1+ild && Celly<=6-idl && state[virtualcount][Cellx-ild-1][Celly+1+idl]==Black){ idl++;ild++; if(idl<=6 && ild<=6)checkWhite(); } else if (Cellx>=1+ild && Celly<=6-idl && state[virtualcount][Cellx-ild-1][Celly+1+idl]==Empty){ state[virtualcount][Cellx][Celly]=0; } //上左方向 if (Cellx>=1+ilu && Celly>=iul+1 && state[virtualcount][Cellx-ilu-1][Celly-iul-1]==White){ if (count==virtualcount && ilu!=0 && iul!=0){ count++; } for(int k=0 ; k <=ilu ; k++){ state[count][Cellx-k][Celly-k]=-1; } } else if (Cellx>=1+ilu && Celly>=iul+1 && state[virtualcount][Cellx-ilu-1][Celly-1-iul]==Black){ iul++;ilu++; if(iul<=6 && ilu<=6)checkWhite(); } else if (Cellx>=1+ilu && Celly>=iul+1 && state[virtualcount][Cellx-ilu-1][Celly-1-iul]==Empty){ state[virtualcount][Cellx][Celly]=0; } if (virtualcount==count)state[count][Cellx][Celly]=0; else state[count][Cellx][Celly]=-1; } // // // ここまでひっくり返す判断 // // // // // 上のメソッドをここで呼び出す。 // // public Board(int x , int y, int c){ //駒をひっくり返すためのメソッド Cellx=x; Celly=y; if(state[count][Cellx][Celly]!=Empty){//置いた場所にもともと何か置いてあったら System.out.println("Cannnot put"); MyCanvas.alart=1;//警告を出して if(MyCanvas.color==1)MyCanvas.color=-1; else if(MyCanvas.color==-1)MyCanvas.color=1;//陣番をかえないようにする } else{ state[count][Cellx][Celly]=c;//何もなかったら置いてみる。 //ここからひっくり返すための判断。 if (c==Black){//置いたのが黒だったら ir=il=iu=id=No=idr=ird=iru=iur=ild=idl=ilu=iul=0;//探索個数を初期化して checkBlack();//ひっくり返せるかチェック } else if(c==White){//置いたのが白だったら ir=il=iu=id=No=idr=ird=iru=iur=ild=idl=ilu=iul=0;//探索個数を初期化 checkWhite();//ひっくり返せるかチェック } } } } //ここまでが盤上のクラス // keyListenerと MouseListenerを使う。ここがメイン。 // // // おもに絵を表示します。ほかには駒の数を数えたり、ゲーム終了を判断したりします。 // class MyCanvas extends Canvas implements KeyListener, MouseListener{ static int color=1;int col;//はじめは黒から int blacknumber=2,whitenumber=2;//それぞれの駒の数を数える static int alart=0;//警告を出すときは1 public MyCanvas(){ super(); Start.Start();//初期化 addKeyListener(this); addMouseListener(this); setSize(Board.BoardWidth,Board.BoardHeight); } Image offScreenImage; Graphics offScreenGraphics; public void update(Graphics g){ if(offScreenImage==null){ offScreenImage=createImage(Board.BoardWidth,Board.BoardHeight); // オフスクリーンイメージを600x400のサイズで作成 offScreenGraphics=offScreenImage.getGraphics(); // オフスクリーンイメージに描画するための Graphics オブジェクト } paint(offScreenGraphics); // 次の画面のイメージを作る. g.drawImage(offScreenImage,0,0,this); // イメージを本物のスクリーンに書き込む } public void paint(Graphics g){ //盤 g.setColor(Color.green); g.fillRect(0,0,Board.BoardWidth,Board.BoardHeight); g.setColor(Color.black); g.fillRect(Board.BoardWidth-150,0,Board.BoardWidth,Board.BoardHeight); //ますめ for(int i = 0 ; i <= Board.CellNumber ; i++){ g.setColor(Color.black); g.drawLine(10,10+Board.CellHeight*i,Board.CellWidth*Board.CellNumber+10,10+Board.CellHeight*i); g.drawLine(10+i*Board.CellWidth,10,10+Board.CellWidth*i,Board.CellWidth*Board.CellNumber+10); } //絵を表示させる for(int j=0 ; j<8; j++){ for(int i=0 ; i<8; i++){ if(Board.state[Board.count][i][j]==1){ g.setColor(Color.black); g.fillOval(15+i*Board.CellWidth,15+j*Board.CellHeight,Board.CellWidth-10,Board.CellHeight-10); } else if(Board.state[Board.count][i][j]==-1){ g.setColor(Color.white); g.fillOval(15+i*Board.CellWidth,15+j*Board.CellHeight,Board.CellWidth-10,Board.CellHeight-10); } } } //文字の表示 g.setColor(Color.white); g.setFont(new Font("Courier",Font.BOLD,20));//どちらの番か if (color==1)g.drawString("Black's turn",510,50); if (color==-1)g.drawString("White's turn",510,50); whitenumber=blacknumber=0; for(int i=0 ;i<8;i++){//白と黒のそれぞれの数を数えて for(int j=0 ;j<8;j++){ if (Board.state[Board.count][i][j]<0){ whitenumber=whitenumber-Board.state[Board.count][i][j]; } if (Board.state[Board.count][i][j]>0){ blacknumber=blacknumber+Board.state[Board.count][i][j]; } } } g.setFont(new Font("Courier",Font.BOLD,15));//それを表示 g.drawString("White : " + whitenumber,510,500); g.drawString("Black : " + blacknumber,510,470); if (alart==1){//置けなかったら警告 g.setColor(Color.yellow); g.drawString("You cannnot",510,250); g.drawString(" put there" ,510,270); alart=0; } if (Board.count==60){//60手打ったら勝ち負けを判定 g.setFont(new Font("Courier",Font.BOLD,30)); g.setColor(Color.red); if (whitenumber>blacknumber)g.drawString("White has won !!",100,250);//白が多かったら else if (whitenumber0){ Board.count=Board.count-1;//手数を一つ減らして交代する。 if(color==1)color=-1; else if(color==-1)color=1; repaint(); } } //Restartボタンを押したら public void Restart(){ Start.Start();//初期値に戻す。 repaint(); } } class Ot extends Frame implements ActionListener{ MenuBar menuBar; Menu fileMenu; MyCanvas game; Button UndoButton,Restart; Ot(){ super("Othello"); menuBar=new MenuBar(); fileMenu=new Menu("File"); fileMenu.add("Exit"); fileMenu.addActionListener(this); setMenuBar(menuBar); // パネル(ボタンなどを配置するための入れ物)部分を作成する. Panel panel=new Panel(); panel.setLayout(new FlowLayout()); panel.add(UndoButton=new Button("undo")); panel.add(Restart=new Button("Restart")); UndoButton.addActionListener(this); Restart.addActionListener(this); // BorderLayoutを用いる. setLayout(new BorderLayout()); // 上部に Panel add(panel,"South"); // 下部に MyCanbasを配置する. add(game=new MyCanvas(),"North"); // キー入力がbuttonに横取りされないようにするため UndoButton.addKeyListener(game); Restart.addKeyListener(game); // 部品をおさめるのに適当と思われるサイズにする. setSize(getPreferredSize()); setVisible(true); } public void actionPerformed(ActionEvent e){ System.out.println(e); Object source=e.getSource(); //undoボタンが押された時 if(source.equals(UndoButton)){ game.undo(); } if(source.equals(Restart)){ Board.count=0; game.Restart(); } // [File]メニューのどれかが選択された時 else if(source.equals(fileMenu)){ String command=e.getActionCommand(); // Exitメニューが選択された時 if(command.equals("Exit")){ System.exit(0); } } } public static void main(String args[]) { // Snowのインスタンスを作成 frameに代入 Ot frame=new Ot(); } }