001:// eightqueen4 : Multi Thread eightqueen(Runnable)
002:
003:import java.awt.* ;
004:import java.awt.event.* ;
005:import javax.swing.* ;
006:import javax.swing.event.* ;
007:
008:public class EightQueen4 extends JFrame
009:                         implements Runnable {
010:
011:    JLabel     title;           // Eight Queen ...
012:    int        count=0;         // 見付かった解の個数
013:    JLabel[][] cell;            // 盤
014:    int        boardSize;       // 盤の大きさ
015:    boolean    trap=true;       // 中断フラグ
016:    boolean    trapOnFound;     // 解が見つかったとき停止するか
017:    final int  trapTime=300;    // 停止する際のwait時間
018:    int[]      pos;             // コマの横位置
019:    int[]      na;              // 斜め上がりの利き筋
020:    int[]      ns;              // 斜め下がりの利き筋
021:    boolean    trapChk=true;    // 利きゴマの表示をするか
022:    int        waitTime=1000;   // 表示時間: JSlider で設定
023:    ImageIcon  queenOn;         // コマの絵(黒)
024:    ImageIcon  queenTry;        // コマの絵(灰)
025:    ImageIcon  queenChk;        // コマの絵(赤)
026:    ImageIcon  queenOff;        // 空白の絵
027:    JButton    gButton;         // 開始・停止ボタン
028:    final static String gButtongo = " go "; // 開始・停止ボタンの表示文字列
029:    final static String gButtonst = "stop"; // 開始・停止ボタンの表示文字列
030:
031:    EightQueen4(int board) {
032:
033:        addWindowListener(new WindowAdapter() {
034:            public void windowClosing(WindowEvent e) { System.exit(0); }
035:        });
036:        getContentPane().setLayout(new BorderLayout());
037:
038:        // 色違いの queen アイコンを読み込み
039:        queenOn  = new ImageIcon( Toolkit.getDefaultToolkit().getImage( "queen-on.gif" ) );  // 黒
040:        queenOff = new ImageIcon( Toolkit.getDefaultToolkit().getImage( "queen-off.gif" ) ); // 空白
041:        queenTry = new ImageIcon( Toolkit.getDefaultToolkit().getImage( "queen-try.gif" ) ); // 灰色
042:        queenChk = new ImageIcon( Toolkit.getDefaultToolkit().getImage( "queen-chk.gif" ) ); // 赤
043:
044:        boardSize = board;                                                    // チェス盤の大きさ
045:        pos = new int[boardSize];                                             // 駒の横位置用の配列
046:        na  = new int[boardSize];                                             // 斜め上がりの利き筋用の配列
047:        ns  = new int[boardSize];                                             // 斜め下がりの利き筋用の配列
048:        cell = new JLabel[boardSize][boardSize];                              // チェス盤のマス目
049:        JPanel backp = new JPanel(new GridLayout(boardSize, boardSize));      // チェス盤
050:        for(int i=0; i<boardSize; i++)
051:            for(int j=0; j<boardSize; j++) {
052:                cell[i][j] = new JLabel( queenOff ) ;                         // マス目を生成
053:                backp.add( cell[i][j] );                                      // マス目をチェス盤に敷き詰め
054:            }
055:        getContentPane().add(backp, SwingConstants.CENTER);                   // チェス盤を Center に貼り付け
056:
057:        title =new JLabel(boardSize + "-Queen   ", SwingConstants.CENTER);    // タイトル N-Queen
058:        getContentPane().add(title, BorderLayout.NORTH);                      //   North に貼り付け
059:
060:        JRadioButton rbutton = new JRadioButton("解が見付かったら停止", true);
061:        trapOnFound = true;                                                   // 初期値は、停止を指定
062:        rbutton.addItemListener(new ItemListener() {
063:            public void itemStateChanged(ItemEvent e) {
064:                if(e.getStateChange()==ItemEvent.DESELECTED) trapOnFound = false;
065:                else                                         trapOnFound = true;
066:            }
067:        });
068:        JRadioButton cbutton = new JRadioButton("利きゴマを表示", true);
069:        trapChk = true;                                                       // 初期値は、表示と指定
070:        cbutton.addItemListener(new ItemListener() {
071:            public void itemStateChanged(ItemEvent e) {
072:                if(e.getStateChange()==ItemEvent.DESELECTED) trapChk = false;
073:                else                                         trapChk = true;
074:            }
075:        });
076:
077:        final JSlider slide = new JSlider(0, waitTime*2, waitTime);  // スライダ
078:        slide.addChangeListener(new ChangeListener() {
079:            public void stateChanged(ChangeEvent e) {
080:                waitTime = slide.getValue();
081:            }
082:        });
083:
084:        gButton = new JButton(gButtongo);
085:        gButton.setFont(new Font("Diolog", Font.BOLD, 16));
086:        gButton.addActionListener(new ActionListener() {
087:            public void actionPerformed(ActionEvent e) {             // トグルボタン
088:                String  s = gButton.getText();
089:                if( s.equals(gButtongo) ) {                          // go であれば
090:                    trap = false;
091:                    gButton.setText(gButtonst);                      //   stop を表示
092:                }
093:                else {                                               // stop であれば
094:                    trap = true;
095:                    gButton.setText(gButtongo);                      //   go を表示
096:                }
097:            }
098:        });
099:
100:        JPanel southpan = new JPanel(new GridLayout(0,1));           // 縦1列に
101:        southpan.add(rbutton);                                       // ラジオボタン
102:        southpan.add(cbutton);                                       // ラジオボタン
103:        southpan.add(slide);                                         // スライダ
104:        southpan.add(gButton);                                       // go/stop ボタン
105:        getContentPane().add(southpan, BorderLayout.SOUTH);          // South に貼り付け
106:    }
107:
108:    void flash(int x, int y) {               // 利きゴマの表示
109:        if(trapChk && waitTime>=5){          // 表示指定 かつ 時間 > 5ミリ
110:            cell[x][y].setIcon( queenChk );  // 利きゴマの色
111:            sleep(waitTime / 2);             // ちら!
112:            cell[x][y].setIcon( queenOn );   // もとの色
113:        }
114:    }
115:
116:    void checkAndSet(int n){                            // n行以降に置いてみる
117:        boolean ok;                                     // 置けるかどうかの判定フラグ
118:        if(n>=boardSize){                               // 最後の行の次を調べようとしている
119:            count++;                                    // 解の個数
120:            System.out.print(count + ". ");             // 画面に表示
121:            for(int i=0; i<boardSize; i++)              //
122:                System.out.print( pos[i] + " ");        //
123:            System.out.println();                       //
124:            title.setText(boardSize +"-Queen "+ count); // タイトルに見つかった個数を表示
125:            if(trapOnFound) {                           // 見つかった時に一時停止
126:                trap = true;                            // 停止フラグを設定
127:                gButton.setText(gButtongo);             // ボタンの表示を変更
128:                sleep(trapTime);                        // 停止
129:            }
130:        }
131:        else {                                          // 調べる行がある場合
132:            for(int k=0; k<boardSize; k++){             // 左端から右端まで
133:                ok=true;                                // 「置ける」と仮設定
134:                sleep(0);                               // 
135:                if(waitTime>5) {                        //
136:                    cell[n][k].setIcon( queenTry ) ;    // 仮に置いた状態を表示
137:                    sleep(waitTime / 5);                //
138:                }                                       //
139:                for(int i=n-1; i>=0; i--){              // 今までに置いた駒について
140:                    if(pos[i]==k)     { ok=false;          // 縦の利き筋に駒が置かれている
141:                                        flash(i, pos[i]);  //
142:                                        break; }           //
143:                    if((n-k)==na[i])  { ok=false;          // 斜め上がりの利き筋
144:                                        flash(i, i-na[i]); //
145:                                        break; }           //
146:                    if((n+k)==ns[i])  { ok=false;          // 斜め下がりの利き筋
147:                                        flash(i, ns[i]-i); //
148:                                        break; }           //
149:                    }                                      //
150:                if(ok){                                 // いずれの利き筋にも駒がなかった
151:                    pos[n] = k;                         // ここに置く
152:                    cell[n][k].setIcon( queenOn ) ;     // 駒のイメージを設定
153:                    sleep(waitTime);                    // ちら! と表示
154:                    na[n]  = n-k;                       // 斜め上がりの利き筋を記録
155:                    ns[n]  = n+k;                       // 斜め下がりの利き筋を記録
156:                    checkAndSet( n+1 );                 // 次の行に置けるかどうかの判定
157:                }                                       // 
158:                cell[n][k].setIcon( queenOff) ;         // 駒の表示を消す
159:            } // for(int k)
160:        }     // if(n>=boardSize)
161:    }         // checkAndSet
162:
163:    void sleep(int time) {                              // 一時停止
164:        if(time>0) {                                    //
165:            try{ Thread.sleep(time);}                   // time ミリ秒
166:            catch(InterruptedException ev) { }          //
167:        }                                               //
168:        while(trap) {                                   // go ボタンが押されるまで停止
169:            try{ Thread.sleep(trapTime);}               //
170:            catch(InterruptedException ev) { }          //
171:        }
172:    }
173:
174:    public void run() {
175:        checkAndSet( 0 );                               // 最上段から開始
176:    }
177:
178:    public static void main(String args[]) {
179:
180:        int board = 8;                                   // パラメタがなければ Eight Queen
181:        if(args.length>0) board = Integer.parseInt(args[0]);
182:
183:        EightQueen4 frame = new EightQueen4(board);      // チェス盤の生成
184:        frame.pack();
185:        frame.setVisible(true);
186:
187:        Thread thread = new Thread( frame );             // 開始
188:        thread.start();
189:    }
190:}