import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.*;

public class OthelloTitanPro extends JFrame {

    // --- プロ仕様設定 ---
    private static final int DEPTH_MID = 14;     // 中盤: 14手読み
    private static final int DEPTH_END = 22;     // 終盤: 22マス空きから完全解析
    private static final int TT_SIZE = 1 << 20;  // 置換表サイズ

    private OthelloPanel boardPanel;
    private JButton btnReplay; // 棋譜再生ボタン

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new OthelloTitanPro());
    }

    public OthelloTitanPro() {
        setTitle("Othello Titan Pro (Fixed Replay Start & Delay)");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        boardPanel = new OthelloPanel(this);
        add(boardPanel, BorderLayout.CENTER);

        JPanel controls = new JPanel();
        controls.setLayout(new FlowLayout());

        String[] modes = {"人(黒) vs AI(白)", "AI(黒) vs 人(白)", "人 vs 人", "AI vs AI"};
        JComboBox<String> modeCombo = new JComboBox<>(modes);
        
        JButton btnHint = new JButton("最強ヒント");
        JButton btnEdit = new JButton("編集モード");
        JButton btnTurnSwitch = new JButton("手番: 黒");
        JButton btnReset = new JButton("初期化");
        btnReplay = new JButton("棋譜再生");

        btnTurnSwitch.setEnabled(false); 
        btnReplay.setEnabled(false);

        controls.add(new JLabel("モード:"));
        controls.add(modeCombo);
        controls.add(btnHint);
        controls.add(btnEdit);
        controls.add(btnTurnSwitch);
        controls.add(btnReset);
        controls.add(btnReplay);
        
        add(controls, BorderLayout.SOUTH);

        // UIアクション定義
        modeCombo.addActionListener(e -> boardPanel.setGameMode(modeCombo.getSelectedIndex()));

        btnHint.addActionListener(e -> boardPanel.showHint());

        btnEdit.addActionListener(e -> {
            boolean isEditing = boardPanel.toggleEditMode();
            if (isEditing) {
                btnEdit.setText("対局再開");
                btnHint.setEnabled(false);
                modeCombo.setEnabled(false);
                btnTurnSwitch.setEnabled(true);
                btnReplay.setEnabled(false);
            } else {
                btnEdit.setText("編集モード");
                btnHint.setEnabled(true);
                modeCombo.setEnabled(true);
                btnTurnSwitch.setEnabled(false);
            }
            btnTurnSwitch.setText("手番: " + (boardPanel.isBlackTurn ? "黒" : "白"));
        });

        btnTurnSwitch.addActionListener(e -> {
            boardPanel.toggleTurn();
            btnTurnSwitch.setText("手番: " + (boardPanel.isBlackTurn ? "黒" : "白"));
        });

        btnReset.addActionListener(e -> {
            boardPanel.resetGame();
            btnEdit.setText("編集モード");
            btnHint.setEnabled(true);
            modeCombo.setEnabled(true);
            btnTurnSwitch.setEnabled(false);
            btnTurnSwitch.setText("手番: 黒");
            btnReplay.setEnabled(false);
        });

        btnReplay.addActionListener(e -> {
            boardPanel.startReplay();
        });

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public void onGameOver() {
        btnReplay.setEnabled(true);
    }

    // ==========================================
    //  Bitboard
    // ==========================================
    static class Bitboard {
        long player;   
        long opponent; 

        private static final long MASK_NOT_A = 0xfefefefefefefefeL; 
        private static final long MASK_NOT_H = 0x7f7f7f7f7f7f7f7fL; 

        public Bitboard(long p, long o) {
            this.player = p;
            this.opponent = o;
        }

        public static Bitboard init() {
            long b = (1L << 28) | (1L << 35);
            long w = (1L << 27) | (1L << 36);
            return new Bitboard(b, w);
        }

        public Bitboard setStoneAt(int index, int type, boolean isBlackTurn) {
            long mask = 1L << index;
            long newPlayer = player & ~mask;     
            long newOpponent = opponent & ~mask; 

            if (isBlackTurn) {
                if (type == 1) newPlayer |= mask;    
                else if (type == 2) newOpponent |= mask; 
            } else {
                if (type == 1) newOpponent |= mask;  
                else if (type == 2) newPlayer |= mask;   
            }
            return new Bitboard(newPlayer, newOpponent);
        }

        public int getStoneColorAt(int index, boolean isBlackTurn) {
            long mask = 1L << index;
            if ((player & mask) != 0) return isBlackTurn ? 1 : 2;
            if ((opponent & mask) != 0) return isBlackTurn ? 2 : 1;
            return 0;
        }

        public long getLegalMoves() {
            long legal = 0;
            long blank = ~(player | opponent);
            long opp = opponent;
            
            // 左
            long t = opp & (player >>> 1) & MASK_NOT_H;
            for(int i=0; i<5; i++) t |= opp & (t >>> 1) & MASK_NOT_H;
            legal |= blank & (t >>> 1) & MASK_NOT_H;

            // 右
            t = opp & (player << 1) & MASK_NOT_A;
            for(int i=0; i<5; i++) t |= opp & (t << 1) & MASK_NOT_A;
            legal |= blank & (t << 1) & MASK_NOT_A;

            // 上
            t = opp & (player >>> 8);
            for(int i=0; i<5; i++) t |= opp & (t >>> 8);
            legal |= blank & (t >>> 8);

            // 下
            t = opp & (player << 8);
            for(int i=0; i<5; i++) t |= opp & (t << 8);
            legal |= blank & (t << 8);

            // 右上
            t = opp & (player >>> 7) & MASK_NOT_A;
            for(int i=0; i<5; i++) t |= opp & (t >>> 7) & MASK_NOT_A;
            legal |= blank & (t >>> 7) & MASK_NOT_A;

            // 左上
            t = opp & (player >>> 9) & MASK_NOT_H;
            for(int i=0; i<5; i++) t |= opp & (t >>> 9) & MASK_NOT_H;
            legal |= blank & (t >>> 9) & MASK_NOT_H;

            // 右下
            t = opp & (player << 9) & MASK_NOT_A;
            for(int i=0; i<5; i++) t |= opp & (t << 9) & MASK_NOT_A;
            legal |= blank & (t << 9) & MASK_NOT_A;

            // 左下
            t = opp & (player << 7) & MASK_NOT_H;
            for(int i=0; i<5; i++) t |= opp & (t << 7) & MASK_NOT_H;
            legal |= blank & (t << 7) & MASK_NOT_H;

            return legal;
        }

        public Bitboard makeMove(long moveBit) {
            long rev = 0;
            for (int k = 0; k < 8; k++) {
                long rev_ = 0;
                long mask = transfer(moveBit, k);
                while (mask != 0 && (mask & opponent) != 0) {
                    rev_ |= mask;
                    mask = transfer(mask, k);
                }
                if ((mask & player) != 0) {
                    rev |= rev_;
                }
            }
            return new Bitboard(opponent ^ rev, player | moveBit | rev);
        }

        private long transfer(long put, int dir) {
            switch(dir) {
                case 0: return (put >>> 8);
                case 1: return (put >>> 7) & MASK_NOT_A;
                case 2: return (put <<  1) & MASK_NOT_A;
                case 3: return (put <<  9) & MASK_NOT_A;
                case 4: return (put <<  8);
                case 5: return (put <<  7) & MASK_NOT_H;
                case 6: return (put >>> 1) & MASK_NOT_H;
                case 7: return (put >>> 9) & MASK_NOT_H;
            }
            return 0;
        }
    }

    // ==========================================
    //  Transposition Table
    // ==========================================
    static class TTEntry {
        long key;
        int score;
        int depth;
        int flag;
        long bestMove;
    }

    static class TranspositionTable {
        TTEntry[] entries = new TTEntry[TT_SIZE];
        static long[][] keys = new long[2][64];
        static long turnKey;

        static {
            java.util.Random r = new java.util.Random(12345);
            for(int i=0; i<2; i++)
                for(int j=0; j<64; j++)
                    keys[i][j] = r.nextLong();
            turnKey = r.nextLong();
        }

        public void clear() {
            Arrays.fill(entries, null);
        }

        public long getHash(Bitboard b) {
            long h = 0;
            long p = b.player;
            long o = b.opponent;
            for(int i=0; i<64; i++) {
                if (((p >>> i) & 1) == 1) h ^= keys[0][i];
                else if (((o >>> i) & 1) == 1) h ^= keys[1][i];
            }
            return h;
        }

        public void store(long hash, int score, int depth, int flag, long bestMove) {
            int idx = (int)(hash & (TT_SIZE - 1));
            TTEntry e = entries[idx];
            if (e == null || e.depth <= depth) {
                e = new TTEntry();
                e.key = hash;
                e.score = score;
                e.depth = depth;
                e.flag = flag;
                e.bestMove = bestMove;
                entries[idx] = e;
            }
        }

        public TTEntry retrieve(long hash) {
            int idx = (int)(hash & (TT_SIZE - 1));
            TTEntry e = entries[idx];
            if (e != null && e.key == hash) return e;
            return null;
        }
    }

    // ==========================================
    //  Pro Solver
    // ==========================================
    static class Solver {
        private static final int[] WEIGHTS = {
            120, -20, 20,  5,  5, 20, -20, 120,
            -20, -40, -5, -5, -5, -5, -40, -20,
             20,  -5, 15,  3,  3, 15,  -5,  20,
              5,  -5,  3,  3,  3,  3,  -5,  5,
              5,  -5,  3,  3,  3,  3,  -5,  5,
             20,  -5, 15,  3,  3, 15,  -5,  20,
            -20, -40, -5, -5, -5, -5, -40, -20,
            120, -20, 20,  5,  5, 20, -20, 120
        };

        private static TranspositionTable tt = new TranspositionTable();

        public static long getBestMove(Bitboard b, int depth) {
            int empty = 64 - Long.bitCount(b.player | b.opponent);
            if (empty <= DEPTH_END) {
                tt.clear();
                return solveExact(b, -Integer.MAX_VALUE, Integer.MAX_VALUE);
            }
            tt.clear();
            long bestMove = 0;
            for (int d = 1; d <= depth; d++) {
                bestMove = solveIterative(b, d);
            }
            return bestMove;
        }

        private static long solveIterative(Bitboard b, int depth) {
            long legal = b.getLegalMoves();
            if (legal == 0) return 0;
            long bestMove = 0;
            int maxScore = -Integer.MAX_VALUE;
            int alpha = -Integer.MAX_VALUE;
            int beta = Integer.MAX_VALUE;
            long[] moves = getSortedMoves(legal, b);
            for (long m : moves) {
                Bitboard next = b.makeMove(m);
                int score = -negamax(next, depth - 1, -beta, -alpha);
                if (score > maxScore) {
                    maxScore = score;
                    bestMove = m;
                    alpha = score;
                }
            }
            return bestMove;
        }
        
        private static long solveExact(Bitboard b, int alpha, int beta) {
            long legal = b.getLegalMoves();
            if (legal == 0) return 0;
            long bestMove = 0;
            int maxScore = -Integer.MAX_VALUE;
            long[] moves = getSortedMoves(legal, b);
            for (long m : moves) {
                Bitboard next = b.makeMove(m);
                int score = -negamax(next, 60, -beta, -alpha);
                if (score > maxScore) {
                    maxScore = score;
                    bestMove = m;
                    alpha = score;
                }
            }
            return bestMove;
        }

        private static int negamax(Bitboard b, int depth, int alpha, int beta) {
            long hash = tt.getHash(b);
            TTEntry entry = tt.retrieve(hash);
            
            if (entry != null && entry.depth >= depth) {
                if (entry.flag == 0) return entry.score;
                if (entry.flag == 1 && entry.score <= alpha) return alpha;
                if (entry.flag == 2 && entry.score >= beta) return beta;
            }

            if (depth <= 0) return evaluate(b);

            long legal = b.getLegalMoves();
            if (legal == 0) {
                Bitboard passed = new Bitboard(b.opponent, b.player);
                if (passed.getLegalMoves() == 0) return finalScore(b);
                return -negamax(passed, depth, -beta, -alpha);
            }

            long ttMove = (entry != null) ? entry.bestMove : 0;
            long[] moves = getSortedMovesWithTT(legal, ttMove);

            int alphaOrig = alpha;
            long bestMove = 0;
            int maxScore = -Integer.MAX_VALUE;

            for (long m : moves) {
                Bitboard next = b.makeMove(m);
                int score = -negamax(next, depth - 1, -beta, -alpha);
                if (score > maxScore) {
                    maxScore = score;
                    bestMove = m;
                }
                if (score > alpha) alpha = score;
                if (alpha >= beta) break;
            }

            int flag = 0;
            if (maxScore <= alphaOrig) flag = 1;
            else if (maxScore >= beta) flag = 2;
            
            tt.store(hash, maxScore, depth, flag, bestMove);
            return maxScore;
        }

        private static long[] getSortedMoves(long legal, Bitboard b) {
            return getSortedMovesWithTT(legal, 0);
        }

        private static long[] getSortedMovesWithTT(long legal, long ttMove) {
            int count = Long.bitCount(legal);
            long[] moves = new long[count];
            int[] scores = new int[count];
            int idx = 0;
            for(long temp = legal; temp != 0; temp &= (temp - 1)) {
                long m = Long.lowestOneBit(temp);
                moves[idx] = m;
                if (m == ttMove) scores[idx] = 10000;
                else scores[idx] = WEIGHTS[Long.numberOfTrailingZeros(m)];
                idx++;
            }
            for(int i=0; i<count-1; i++) {
                for(int j=0; j<count-1-i; j++) {
                    if(scores[j] < scores[j+1]) {
                        int ts = scores[j]; scores[j] = scores[j+1]; scores[j+1] = ts;
                        long tm = moves[j]; moves[j] = moves[j+1]; moves[j+1] = tm;
                    }
                }
            }
            return moves;
        }

        private static int evaluate(Bitboard b) {
            int score = 0;
            long p = b.player;
            long o = b.opponent;
            while (p != 0) {
                long m = Long.lowestOneBit(p);
                score += WEIGHTS[Long.numberOfTrailingZeros(m)];
                p ^= m;
            }
            while (o != 0) {
                long m = Long.lowestOneBit(o);
                score -= WEIGHTS[Long.numberOfTrailingZeros(m)];
                o ^= m;
            }
            score += (Long.bitCount(b.getLegalMoves()) * 5);
            return score;
        }

        private static int finalScore(Bitboard b) {
            int diff = Long.bitCount(b.player) - Long.bitCount(b.opponent);
            return diff > 0 ? 10000 + diff : -10000 + diff;
        }
    }

    // ==========================================
    //  UI Panel
    // ==========================================
    class OthelloPanel extends JPanel implements MouseListener {
        private OthelloTitanPro parentFrame;
        
        Bitboard currentBoard;
        boolean isBlackTurn = true;
        
        // 開始局面のスナップショット
        Bitboard startBoardSnapshot;
        boolean startTurnSnapshot = true;

        boolean gameOver = false;
        int gameMode = 0; 
        boolean isEditMode = false;
        long hintBit = 0; 

        List<Long> moveHistory = new ArrayList<>();
        boolean isReplaying = false;
        Timer replayTimer;
        int replayIndex = 0;

        final int CELL_SIZE = 80;

        public OthelloPanel(OthelloTitanPro frame) {
            this.parentFrame = frame;
            setPreferredSize(new Dimension(640, 680));
            addMouseListener(this);
            resetGame();
        }

        public void resetGame() {
            currentBoard = Bitboard.init();
            isBlackTurn = true;
            
            // リセット時は標準初期配置をスナップショットにする
            startBoardSnapshot = currentBoard;
            startTurnSnapshot = true;

            gameOver = false;
            isEditMode = false;
            hintBit = 0;
            isReplaying = false;
            if(replayTimer != null) replayTimer.stop();
            
            moveHistory.clear();
            
            repaint();
            checkTurn();
        }

        public void setGameMode(int mode) {
            this.gameMode = mode;
            if (!isEditMode && !gameOver && !isReplaying) checkTurn();
        }

        public boolean toggleEditMode() {
            isEditMode = !isEditMode;
            hintBit = 0;
            
            if (isEditMode) {
                // 編集モードに入った瞬間、一旦履歴はクリア
                moveHistory.clear();
            } else {
                // 編集モード終了時（対局再開）、この局面を「リプレイ開始地点」として保存
                startBoardSnapshot = currentBoard;
                startTurnSnapshot = isBlackTurn;
                
                // ここから新しい履歴を開始
                moveHistory.clear();
                
                gameOver = false;
                checkTurn();
            }
            repaint();
            return isEditMode;
        }

        public void toggleTurn() {
            isBlackTurn = !isBlackTurn;
            currentBoard = new Bitboard(currentBoard.opponent, currentBoard.player);
            // 手番変更時も新しい開始地点とみなす
            startBoardSnapshot = currentBoard;
            startTurnSnapshot = isBlackTurn;
            moveHistory.clear();
            repaint();
        }

        public void startReplay() {
            if (moveHistory.isEmpty()) return;
            
            isReplaying = true;
            // 編集終了時のスナップショット局面に戻す
            currentBoard = startBoardSnapshot;
            isBlackTurn = startTurnSnapshot;
            
            gameOver = false;
            hintBit = 0;
            replayIndex = 0;
            
            repaint();
            
            // ★変更点: タイマーの初期遅延を3秒(3000ms)に設定
            replayTimer = new Timer(3000, e -> playNextReplayMove());
            replayTimer.setInitialDelay(3000); 
            replayTimer.start();
        }

        private void playNextReplayMove() {
            if (replayIndex >= moveHistory.size()) {
                replayTimer.stop();
                isReplaying = false;
                gameOver = true;
                repaint();
                return;
            }

            long move = moveHistory.get(replayIndex);
            replayIndex++;

            if (move == 0) {
                // パス
                currentBoard = new Bitboard(currentBoard.opponent, currentBoard.player);
                isBlackTurn = !isBlackTurn;
            } else {
                // 通常着手
                currentBoard = currentBoard.makeMove(move);
                isBlackTurn = !isBlackTurn;
            }
            repaint();
        }

        public void showHint() {
            if (gameOver || isEditMode || isCurrentPlayerAI() || isReplaying) return;
            new Thread(() -> {
                int emptyCount = 64 - Long.bitCount(currentBoard.player | currentBoard.opponent);
                int depth = (emptyCount <= DEPTH_END) ? 60 : DEPTH_MID;
                long best = Solver.getBestMove(currentBoard, depth);
                SwingUtilities.invokeLater(() -> {
                    hintBit = best;
                    repaint();
                });
            }).start();
        }

        private boolean isCurrentPlayerAI() {
            if (isEditMode || isReplaying) return false;
            if (gameMode == 3) return true; 
            if (gameMode == 2) return false; 
            if (gameMode == 0) return !isBlackTurn;
            if (gameMode == 1) return isBlackTurn;
            return false;
        }

        private void checkTurn() {
            if (gameOver || isEditMode || isReplaying) return;

            long legal = currentBoard.getLegalMoves();
            if (legal == 0) {
                Bitboard passed = new Bitboard(currentBoard.opponent, currentBoard.player);
                if (passed.getLegalMoves() == 0) {
                    gameOver = true;
                    hintBit = 0;
                    repaint();
                    parentFrame.onGameOver();
                    return;
                }
                
                moveHistory.add(0L); 
                
                currentBoard = passed;
                isBlackTurn = !isBlackTurn;
                hintBit = 0;
                repaint();
                
                javax.swing.Timer t = new javax.swing.Timer(500, e -> checkTurn());
                t.setRepeats(false);
                t.start();
                return;
            }

            if (isCurrentPlayerAI()) {
                hintBit = 0;
                repaint();
                new Thread(() -> {
                    try { Thread.sleep(200); } catch(Exception e){}
                    int emptyCount = 64 - Long.bitCount(currentBoard.player | currentBoard.opponent);
                    int depth = (emptyCount <= DEPTH_END) ? 60 : DEPTH_MID;
                    long best = Solver.getBestMove(currentBoard, depth);
                    SwingUtilities.invokeLater(() -> executeMove(best));
                }).start();
            }
        }

        private void executeMove(long moveBit) {
            if (moveBit == 0) return;
            
            moveHistory.add(moveBit);
            
            currentBoard = currentBoard.makeMove(moveBit);
            isBlackTurn = !isBlackTurn;
            hintBit = 0;
            repaint();
            checkTurn();
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            
            for (int i = 0; i < 64; i++) {
                int r = i / 8;
                int c = i % 8;
                int x = c * CELL_SIZE;
                int y = r * CELL_SIZE;

                g2.setColor(new Color(34, 139, 34));
                g2.fillRect(x, y, CELL_SIZE, CELL_SIZE);
                g2.setColor(Color.BLACK);
                g2.drawRect(x, y, CELL_SIZE, CELL_SIZE);

                long mask = 1L << i;
                if ((currentBoard.player & mask) != 0) {
                    g2.setColor(isBlackTurn ? Color.BLACK : Color.WHITE);
                    g2.fillOval(x+8, y+8, CELL_SIZE-16, CELL_SIZE-16);
                } else if ((currentBoard.opponent & mask) != 0) {
                    g2.setColor(isBlackTurn ? Color.WHITE : Color.BLACK);
                    g2.fillOval(x+8, y+8, CELL_SIZE-16, CELL_SIZE-16);
                }
            }

            if (hintBit != 0) {
                int hintIdx = Long.numberOfTrailingZeros(hintBit);
                int r = hintIdx / 8;
                int c = hintIdx % 8;
                g2.setColor(Color.MAGENTA);
                g2.setStroke(new BasicStroke(5));
                g2.drawOval(c * CELL_SIZE + 10, r * CELL_SIZE + 10, CELL_SIZE - 20, CELL_SIZE - 20);
            }

            if (!isCurrentPlayerAI() && !gameOver && !isEditMode && !isReplaying) {
                long legal = currentBoard.getLegalMoves();
                g2.setColor(new Color(0, 0, 0, 60)); 
                for(int i=0; i<64; i++) {
                    if ((legal & (1L << i)) != 0) {
                        int r = i / 8;
                        int c = i % 8;
                        g2.fillOval(c*CELL_SIZE+35, r*CELL_SIZE+35, 10, 10);
                    }
                }
            }

            g2.setColor(Color.BLACK);
            g2.fillRect(0, 640, 640, 40);
            g2.setColor(Color.WHITE);
            g2.setFont(new Font("SansSerif", Font.BOLD, 16));
            
            String msg = "";
            if (isReplaying) {
                int moves = replayIndex;
                msg = "【棋譜再生中】 " + moves + "手目 (3秒間隔で再生中...)";
            } else if (isEditMode) {
                msg = "【編集】左:黒 / 右:白 (現在の手番: " + (isBlackTurn ? "黒" : "白") + ")";
            } else if (gameOver) {
                int b = Long.bitCount(isBlackTurn ? currentBoard.player : currentBoard.opponent);
                int w = Long.bitCount(isBlackTurn ? currentBoard.opponent : currentBoard.player);
                msg = "終局: 黒 " + b + " - 白 " + w + " (「棋譜再生」で振り返り可能)";
            } else {
                msg = "手番: " + (isBlackTurn ? "黒" : "白") + (isCurrentPlayerAI() ? " (AI長考中)" : " (あなた)");
                if (hintBit != 0) msg += " ※最強手を表示";
            }
            g2.drawString(msg, 10, 665);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            int c = e.getX() / CELL_SIZE;
            int r = e.getY() / CELL_SIZE;
            if (c < 0 || c >= 8 || r < 0 || r >= 8) return;
            int i = r * 8 + c;

            if (isReplaying) return;

            if (isEditMode) {
                int targetColor = 0;
                if (SwingUtilities.isLeftMouseButton(e)) targetColor = 1; 
                else if (SwingUtilities.isRightMouseButton(e)) targetColor = 2;
                if (targetColor == 0) return;

                int currentColor = currentBoard.getStoneColorAt(i, isBlackTurn);
                if (currentColor == targetColor) targetColor = 0;
                
                currentBoard = currentBoard.setStoneAt(i, targetColor, isBlackTurn);
                moveHistory.clear(); 
                repaint();
                return;
            }

            if (gameOver || isCurrentPlayerAI()) return;

            long mask = 1L << i;
            long legal = currentBoard.getLegalMoves();
            if ((legal & mask) != 0) {
                executeMove(mask);
            }
        }
        public void mousePressed(MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}
    }
}