实现MVC模型

时间:2017-05-09 15:40:25

标签: java model

每当我在SO上需要帮助时,我都要求发布遵循MVC模型的代码。所以上网了,阅读了一些关于模型的主题,但仍然无法正确理解这个概念。以下面的代码为例,我试图让它适应MVC模型。有谁知道如何实现这个目标?

下面的代码绘制一个二维阵列网格,在单元格内绘制椭圆,搜索单元格'邻居,找到通过单元格的路径,然后绘制路径中所有单元格传递的线条。

它包含测试用例,可帮助您更好地了解其工作原理。

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public final class Pha extends JFrame {

    //a collection of cells in the path.
    //each cell represented by [row,col]
    private Stack<int[]> path;
    // legth 
    //a path shorter than min can not surround any cell
    private static final int MIN_PATH_LENGTH = 4;

    //a collection of cells that has been tested
    private ArrayList<int[]> checked;

    //represents the cell where the search starts from
    int[] origin;
    //represents the token of the origin
    Token originToken;

    private static int ROWS = 15;
    private static int COLS = ROWS;
    private static int cellSize = 15;
    private static int canvasWidth = (cellSize * COLS) + (ROWS *4) ;
    private static int canvasHeight = cellSize * ROWS ;
    private static int gridWidth = 1;
    private static int halfGridWidth = gridWidth / 2;

    private static int cellPadding = cellSize / 5;
    private static int symbolSize = cellSize - (cellPadding * 2);
    private static int symbolStrokeWidth = 3;

    private enum Token{
        VIDE, CERCLE_ROUGE, CERCLE_BLEU
    }

    private Token[][] board;
    private final DrawCanvas canvas;
    private GameState actualState;
    public enum GameState{
        JOUE, NUL, CERCLE_ROUGE_GAGNE, CERCLE_BLEU_GAGNE
    }
    private Token actualPlayer;

    //used to set different test data
    private static int testNumber = 0;

    public Pha(){
        canvas = new DrawCanvas();
        canvas.setPreferredSize(new Dimension(canvasWidth, canvasHeight));

       canvas.addMouseListener(new MouseAdapter(){
            @Override
            public void mouseClicked(MouseEvent e){
                int x = e.getX();
                int y = e.getY();

                int selectedRow = y / cellSize;
                int selectedCol = x / cellSize;

                if(actualState == GameState.JOUE){
                    if(selectedRow >= 0 && selectedRow < ROWS && selectedCol >= 0
                            && selectedCol < COLS && board[selectedRow][selectedCol] == Token.VIDE){
                        board[selectedRow][selectedCol] = actualPlayer;
                        updateGame(actualPlayer, selectedRow, selectedCol);
                        actualPlayer = (actualPlayer == Token.CERCLE_BLEU) ? Token.CERCLE_ROUGE : Token.CERCLE_BLEU;

                         findPath(new int[]{selectedRow, selectedCol});
                    }
                }else{
                    initGame();
                }
                repaint();
            }


        });


        Container cp = getContentPane();
        cp.setLayout(new BorderLayout());
        cp.add(canvas, BorderLayout.EAST);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        setTitle("Pha par esQmo");
        setVisible(true);

        board = new Token[ROWS][COLS];
        initGame();

        //fill some data for testing
        int[] origin = loadtestData(board);
        //int[] origin = new int[] {this.getX(),this.getY()};

        findPath(origin);

    }

    private void initGame(){

        for(int ligne = 0; ligne < ROWS; ++ligne){
            for(int colonne = 0; colonne < COLS; ++colonne){
                board[ligne][colonne] = Token.VIDE;

            }
        }
        actualState = GameState.JOUE;
        actualPlayer = Token.CERCLE_ROUGE;
    }
    public void updateGame(Token theSeed, int ligneSelectionnee, int colonneSelectionnee) {
     /* if (aGagne(theSeed, ligneSelectionnee, colonneSelectionnee)) {  // check for win
         actualState= (theSeed == Token.CERCLE_ROUGE) ? GameState.CERCLE_ROUGE_GAGNE : GameState.CERCLE_BLEU_GAGNE;
      } else if (estNul()) {  // check for draw
         actualState = GameState.CERCLE_BLEU_GAGNE;       
      }*/
      // Otherwise, no change to current state (still GameState.PLAYING).
   }


    //search for a path
    private void findPath(int[] origin) {

        //initialize path and checked
        path = new Stack<>();
        this.origin = origin;

        int row = origin[0], col =  origin[1];

        //represents the token of the origin
        originToken = board[row][col];

        //initialize list of checked items
        checked = new  CellsList();

        boolean found = findPath(row, col);

        if(found) {
            printPath();
        } else {
            System.out.println("No path found");
        }
    }

    //recursive method to find path. a cell is represented by its row, col
    //returns true when path was found
    private boolean findPath(int row, int col) {

        //check if cell has the same token as origin
        if(board[row][col] != originToken) {
            return false;
        }

        int[] cell = new int[] {row, col};

        //check if this cell was tested before to avoid checking again
        if(checked.contains(cell)) {
            return false;
        }

        //get cells neighbors
        CellsList neighbors = getNeighbors(row, col);

        //check if solution found. If path size > min and cell
        //neighbors contain the origin, it means that path was found
        if((path.size() > MIN_PATH_LENGTH) && neighbors.contains(origin) ) {

            path.add(cell);
            return true;
        }

        //add cell to checked
        checked.add(cell);

        //add cell to path
        path.add(cell);

        //if path was not found check cell neighbors
        for(int[] neighbor : neighbors ) {

            boolean found = findPath(neighbor[0],neighbor[1]);
            if(found) {
                return true;
            }
        }

        //path not found
        path.pop(); //remove last element from stack
        return false;
    }

    //return a list of all neighbors of cell row, col
    private CellsList getNeighbors(int  row, int col) {

        CellsList neighbors = new CellsList();

        for (int colNum = col - 1 ; colNum <= (col + 1) ; colNum +=1  ) {

            for (int rowNum = row - 1 ; rowNum <= (row + 1) ; rowNum +=1  ) {

                if(!((colNum == col) && (rowNum == row))) {

                    if(withinGrid (rowNum, colNum )  ) {

                        neighbors.add(new int[] {rowNum, colNum});

                    }
                }
            }
        }

        return neighbors;
    }

    private boolean withinGrid(int colNum, int rowNum) {

        if((colNum < 0) || (rowNum <0) ) {
            return false;
        }
        if((colNum >= COLS) || (rowNum >= ROWS)) {
            return false;
        }
        return true;
    }

    private void printPath() {
        System.out.print("Path : " );
        for(int[] cell : path) {
            System.out.print(Arrays.toString(cell));
        }
        System.out.println("");

    }



    class DrawCanvas extends JPanel{

        @Override
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            setBackground(Color.WHITE);

            g.setColor(Color.BLACK);
            for(int ligne = 1; ligne < ROWS; ++ligne){
                g.fillRoundRect(0, (cellSize * ligne) - halfGridWidth, canvasWidth - 1,
                        gridWidth, gridWidth, gridWidth);
            }
            for(int colonne = 1; colonne < COLS; ++colonne){
                g.fillRoundRect((cellSize * colonne) - halfGridWidth, 0
                        , gridWidth, canvasHeight - 1,
                        gridWidth, gridWidth);
            }


            Graphics2D g2d = (Graphics2D)g;
            g2d.setStroke(new BasicStroke(symbolStrokeWidth,
                    BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
            for(int ligne = 0; ligne < ROWS; ++ligne){
                for(int colonne = 0; colonne < COLS; ++colonne){
                    int x1 = (colonne * cellSize) + cellPadding;
                    int y1 = (ligne * cellSize) + cellPadding;

                    if(board[ligne][colonne] == Token.CERCLE_ROUGE){
                        g2d.setColor(Color.RED);
                        g2d.drawOval(x1, y1, symbolSize, symbolSize);
                        g2d.fillOval(x1, y1, symbolSize, symbolSize);
                    } else
                        if(board[ligne][colonne] == Token.CERCLE_BLEU){
                            int x2 = (colonne * cellSize) + cellPadding;
                            g2d.setColor(Color.BLUE);
                            g2d.drawOval(x1, y1, symbolSize, symbolSize);
                            g2d.fillOval(x2, y1, symbolSize, symbolSize);
                        }
                }
            }


            //draw lines
           /* Stack<int[]> drawingPath = new Stack<>();
            drawingPath.addAll(path);
            drawingPath.add(drawingPath.get(0));


            Point startPoint = null;
            for (int[] cell : path){
             Point endPoint = new Point((cell[1] * cellSize) + cellSize / 2, (cell[0] * cellSize) + cellSize / 2);

            if (startPoint != null) {
            //Graphics2D g2d = (Graphics2D) g;
            g2d.setStroke(new BasicStroke(symbolStrokeWidth,
                    BasicStroke.CAP_SQUARE, BasicStroke.CAP_BUTT));
            g2d.draw(new Line2D.Double(startPoint, endPoint));

            }
            startPoint = endPoint;
            } 
         */
    Stack<int[]> drawingPath = new Stack<>();
    drawingPath.addAll(path);
    drawingPath.add(drawingPath.get(0));

    Point startPoint = null;
    for (int[] cell : drawingPath) {
        System.out.println(cell[1] + "," + cell[0]);
        Point endPoint = new Point((cell[1] * cellSize) + cellSize / 2, (cell[0] * cellSize) + cellSize / 2);
        if (startPoint != null) {
            g2d.draw(new Line2D.Double(startPoint, endPoint));
        }
        startPoint = endPoint;
    }

        }
    }

    public static void main(String[] args){

        //set test number. Change values between 0-2 to run different tests
        testNumber = 2;
        SwingUtilities.invokeLater(() -> {
           // new Pha();
            Pha pha = new Pha();
        });
    }

    //method used for testing only: load test data
    private static int[] loadtestData(Token[][] board) {

        switch (testNumber) {

            case 1:
                board[6][6] = Token.CERCLE_ROUGE; //origin and target
                board[6][7] = Token.CERCLE_ROUGE;
                board[6][8] = Token.CERCLE_BLEU;
                board[9][9] = Token.CERCLE_BLEU;

                board[7][6] = Token.CERCLE_ROUGE;
                board[7][7] = Token.CERCLE_BLEU;
                board[7][8] = Token.CERCLE_BLEU;

                board[8][6] = Token.CERCLE_ROUGE;
                board[8][7] = Token.CERCLE_ROUGE;
                board[8][8] = Token.CERCLE_ROUGE;

                board[5][7] = Token.CERCLE_ROUGE;
                board[5][8] = Token.CERCLE_ROUGE;
                board[5][9] = Token.CERCLE_ROUGE;
                board[6][9] = Token.CERCLE_ROUGE;
                board[7][9] = Token.CERCLE_ROUGE;
                return new int[] {6,6};

            case 2:
                //line 3
                board[3][6] = Token.CERCLE_ROUGE;
                //line 4
                board[4][4] = Token.CERCLE_BLEU; //origin
                board[4][5] = Token.CERCLE_BLEU;
                board[4][6] = Token.CERCLE_BLEU;
                board[4][8] = Token.CERCLE_BLEU;
                //line5
                board[5][3] = Token.CERCLE_BLEU;
                board[5][5] = Token.CERCLE_ROUGE;
                board[5][7] = Token.CERCLE_BLEU;
                board[5][8] = Token.CERCLE_ROUGE;
                board[5][9] = Token.CERCLE_BLEU;
                //line 6
                board[6][2] = Token.CERCLE_BLEU;
                board[6][3] = Token.CERCLE_ROUGE;
                board[6][4] = Token.CERCLE_ROUGE;
                board[6][5] = Token.CERCLE_ROUGE;
                board[6][6] = Token.CERCLE_ROUGE;
                board[6][7] = Token.CERCLE_ROUGE;
                board[6][8] = Token.CERCLE_ROUGE;
                board[6][9] = Token.CERCLE_BLEU;
                //line 7
                board[7][3] = Token.CERCLE_BLEU;
                board[7][4] = Token.CERCLE_BLEU;
                board[7][5] = Token.CERCLE_BLEU;
                board[7][6] = Token.CERCLE_BLEU;
                board[7][7] = Token.CERCLE_ROUGE;
                board[7][8] = Token.CERCLE_BLEU;
                //line 8
                board[8][3] = Token.CERCLE_ROUGE;
                board[8][7] = Token.CERCLE_BLEU;
                board[8][8] = Token.CERCLE_ROUGE;
                board[8][9] = Token.CERCLE_BLEU;
                //line 9
                board[9][7] = Token.CERCLE_ROUGE;
                board[9][8] = Token.CERCLE_BLEU;
                board[9][9] = Token.CERCLE_ROUGE;
                //line 10
                board[10][8] = Token.CERCLE_ROUGE;
                board[10][9] = Token.CERCLE_ROUGE;

                return new int[] {4,4};

            case 0: default:
                    board[6][6] = Token.CERCLE_ROUGE;
                    board[6][7] = Token.CERCLE_ROUGE; //origin and target
                    board[6][8] = Token.CERCLE_BLEU;

                    board[7][6] = Token.CERCLE_ROUGE;
                    board[7][7] = Token.CERCLE_BLEU;
                    board[7][8] = Token.CERCLE_ROUGE;

                    board[8][6] = Token.CERCLE_ROUGE;
                    board[8][7] = Token.CERCLE_ROUGE;
                    board[8][8] = Token.CERCLE_ROUGE;

                    board[5][7] = Token.CERCLE_ROUGE;
                    board[5][8] = Token.CERCLE_ROUGE;
                    board[5][9] = Token.CERCLE_ROUGE;
                    board[6][9] = Token.CERCLE_ROUGE;
                    board[7][9] = Token.CERCLE_ROUGE;
                    return new int[] {6,7};
        }
    }
}

class CellsList extends ArrayList<int[]>{

    @Override  //override to check by the value of int[]
    public boolean contains(Object o) {

        for (int[] a : this) {
            if(Arrays.equals(a, (int[]) o)) {
                return true;
            }
        }
        return false;
    }
}

2 个答案:

答案 0 :(得分:3)

我的回答是基于this帖子中Hovercraft Full Of Eels建议的MCV模型。
我努力简化它,添加一些注释,并将其改编为您的代码。
我还添加了路径查找计算 该代码包含7个类。我将每个班级都放在一个单独的文件中,所有文件都存在于同一个文件夹中:


主要课程

import javax.swing.SwingUtilities;

public class MvcPha {

    public static void main(String[] args) {

        // run all on the Swing event thread
        SwingUtilities.invokeLater(() -> {
            Model model = new Model();
            View view = new View();
            new Control(model, view);
        });
    }
}

控制类

import java.beans.IndexedPropertyChangeEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.SwingUtilities;
public class Control {

    private Model model;
    private View view;
    private Token lastToken;

    public Control(Model model, View view) {

        this.model = model;
        this.view = view;
        lastToken = Token.CERCLE_BLEU;

        view.createGrid(model.getRows(), model.getCols());

        view.addPropertyChangeListener(new ViewListener());
        model.addPropertyChangeListener(Model.TOKEN, new ModelListener());
        view.start();
    }

    //a listener added to view panel to listen to property  changes events
    //fired by the mouse listener of each cell
    private class ViewListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(View.CELL_SELECTION)) {
                int row = view.getSelectedRow();
                int col = view.getSelectedCol();

                Token token = model.getToken(row, col);
                if (token == Token.VIDE) {

                    lastToken = (lastToken == Token.CERCLE_BLEU) ?
                            Token.CERCLE_ROUGE : Token.CERCLE_BLEU;
                    token = lastToken;
                }
                model.setToken(token, row, col);
            }
        }
    }

    //listener added to model to listen to token changes. used to updated view
    //when token changes
    private class ModelListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            IndexedPropertyChangeEvent iEvt = (IndexedPropertyChangeEvent)evt;
            int index = iEvt.getIndex();
            int row = index / Model.COLS;
            int col = index % Model.COLS;
            Token token = (Token) evt.getNewValue();

            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {

                    view.setCell(token, row, col);
                    view.setPath(model.getPath());
                    view.refresh();
                }
            });
        }
    }
}

模型类

import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;

public class Model {

    public static final int ROWS = 20;
    public static final int COLS = ROWS;
    public static final String TOKEN = "token";
    private Token[][] grid = new Token[ROWS][COLS];
    private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);

    //a stack representing cells in the path
    private Path path;

    public Model() {

        //set entire grid to  Token.VIDE
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {
                grid[r][c] = Token.VIDE;
            }
        }
    }

    Token getToken(int row, int col) {

        return grid[row][col];
    }

     void setToken(Token token, int row, int col) {

        Token oldValue = grid[row][col];
        Token newValue = token;
        grid[row][col] = token;
        int index = (row * grid[row].length) + col;
        pcSupport.fireIndexedPropertyChange(TOKEN, index, oldValue, newValue);

        findPath(new int[] {row, col});
    }

    void addPropertyChangeListener(String name, PropertyChangeListener listener) {

        pcSupport.addPropertyChangeListener(name, listener);
    }

    int getRows() {
        return ROWS;
    }

    int getCols() {
        return COLS;
    }

    //search for a path
    private void findPath(int[] origin) {

        //initialize path and checked
        path = new Path(grid);
        path.findPath(origin);
    }

    CellsList getPath() {

        return (path == null ) ? null : path.getPath();
    }
}

查看课程

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeListener;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class View {

    private static final int ICON_W = 18;
    public static final String CELL_SELECTION = "cell selection";
    private int rows;

    private JPanel mainPanel;
    private JLabel[][] grid;
    private Map<Token, Icon> iconMap = new EnumMap<>(Token.class);
    private int selectedRow;
    private int selectedCol;

    //a collection of cells representing a path
    private CellsList path;

    View() {

        iconMap.put(Token.VIDE, createIcon(new Color(0, 0, 0, 0)));
        iconMap.put(Token.CERCLE_BLEU, createIcon(Color.BLUE));
        iconMap.put(Token.CERCLE_ROUGE, createIcon(Color.RED));

        mainPanel = new JPanel();
    }

    private Icon createIcon(Color color) {

        BufferedImage img = new BufferedImage(ICON_W, ICON_W, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(color);
        g2.fillOval(1, 1, ICON_W - 2, ICON_W - 2);
        g2.dispose();

        return new ImageIcon(img);
    }

    void createGrid(int rows, int cols) {

        MyMouseListener listener = new MyMouseListener();
        setRows(rows);

        mainPanel.setLayout(new GridLayout(rows, cols, 1, 1));
        mainPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        mainPanel.setBackground(Color.BLACK);
        grid = new JLabel[rows][cols];
        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {
                grid[r][c] = new JLabel(iconMap.get(Token.VIDE));
                grid[r][c].addMouseListener(listener);
                grid[r][c].setOpaque(true);
                grid[r][c].setBackground(Color.WHITE);
                mainPanel.add(grid[r][c]);
            }
        }
    }

    int getSelectedRow() {
        return selectedRow;
    }

    int getSelectedCol() {
        return selectedCol;
    }

    void setCell(Token token, int row, int col) {

        grid[row][col].setIcon(iconMap.get(token));
    }

    int getRows() {
        return rows;
    }

    void setRows(int rows) {
        this.rows = rows;
    }

    //added to each cell to listen to mouse clicks
    //fires property change with cell index
    private class MyMouseListener extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            JLabel selection = (JLabel) e.getSource();
            for (int r = 0; r < grid.length; r++) {
                for (int c = 0; c < grid[r].length; c++) {
                    if (selection == grid[r][c]) {
                        selectedRow = r;
                        selectedCol = c;
                        int index = (r * grid[r].length) + c;
                        mainPanel.firePropertyChange(CELL_SELECTION, -1, index);
                    }
                }
            }
        }
    }

    void start() {

        JFrame frame = new JFrame("MVC Pha");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    //add listener to listen to property changes fired by MyMouseListener
    void addPropertyChangeListener(PropertyChangeListener viewListener) {

        mainPanel.addPropertyChangeListener(viewListener);
    }

    void setPath(CellsList path) {

        this.path = path;
        if(path != null) {
            drawPath();
        }
    }

    //highlight path by changing background color. 
    //It can be changed to draw lines between cells
    private void drawPath() {

        for (int r = 0; r < grid.length; r++) {
            for (int c = 0; c < grid[r].length; c++) {

                if((path != null) && path.contains(new int[] {r,c})) {
                    grid[r][c].setBackground(Color.YELLOW);
                } else {
                    grid[r][c].setBackground(Color.WHITE);
                }
            }
        }
    }

    void refresh() {

        mainPanel.repaint();
    }
}
用于处理路径查找的

路径类(仍需要一些调试)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;

//a stack representing cells in the path
//each cell represented by [row,col]
class Path extends Stack<int[]>{

    private Token[][] grid;

    //a path shorter than min can not surround any cell
    private static final int MIN_PATH_LEGTH = 3;

    //a collection of cells that has been tested
    private ArrayList<int[]>checked;

    //represents the cell where the search starts from
    int[] origin;
    //represents the token of the origin
    Token originToken;

    private int rows;
    private int cols;

    Path(Token[][] grid){

        this.grid = grid;
        rows = grid.length;
        cols = grid[0].length;
    }

    //search for a path
    boolean findPath(int[] origin) {

        this.origin = origin;

        int row = origin[0] , col =  origin[1];

        //represents the token of the origin
        originToken = grid[row][col];

        //initialize list of checked items
        checked = new  CellsList();

        boolean found = findPath(row, col);

        if(found) {
            printPath();
        } else {
            System.out.println("No path found");
        }

        return found;
    }

    //recursive method to find path. a cell is represented by its row, col
    //returns true when path was found
    private boolean findPath(int row, int col) {

        //check if cell has the same token as origin
        if(grid[row][col] != originToken) {
            return false;
        }

        int[] cell = new int[] {row, col};

        //check if this cell was tested before to avoid checking again
        if(checked.contains(cell)) {
            return false;
        }

        //get cells neighbors
        CellsList neighbors = getNeighbors(row, col);

        //check if solution found. If path size > min and cell
        //neighbors contain the origin it means that path was found
        if((size() >= MIN_PATH_LEGTH) && neighbors.contains(origin)  ) {

            add(cell);
            return true;
        }

        //add cell to checked
        checked.add(cell);

        //add cell to path
        add(cell);

        //if path was not found check cell neighbors
        for(int[] neighbor : neighbors ) {

            boolean found = findPath(neighbor[0],neighbor[1]);
            if(found) {
                return true;
            }
        }

        //path not found
        pop(); //remove last element from stack
        return false;
    }

    //return a list of all neighbors of cell row, col
    private CellsList getNeighbors(int  row, int col) {

        CellsList neighbors = new CellsList();

        for (int colNum = col - 1 ; colNum <= (col + 1) ; colNum +=1  ) {

            for (int rowNum = row - 1 ; rowNum <= (row + 1) ; rowNum +=1  ) {

                if(!((colNum == col) && (rowNum == row))) {

                    if(withinGrid (rowNum, colNum )  ) {

                        neighbors.add( new int[] {rowNum, colNum});
                    }
                }
            }
        }

        return neighbors;
    }

    private boolean withinGrid(int colNum, int rowNum) {

        if((colNum < 0) || (rowNum <0) ) {
            return false;
        }
        if((colNum >= cols) || (rowNum >= rows)) {
            return false;
        }
        return true;
    }

    //use for testing
    private void printPath() {
        System.out.print("Path : " );
        for(int[] cell : this) {
            System.out.print(Arrays.toString(cell));
        }
        System.out.println("");
    }

    public CellsList getPath() {

        CellsList cl = new CellsList();
        cl.addAll(this);
        return cl;
    }
}
OP中的

令牌枚举

public enum Token {
    VIDE, CERCLE_BLEU, CERCLE_ROUGE
}

简单集合覆盖

import java.util.ArrayList;
import java.util.Arrays;

class CellsList extends ArrayList<int[]>{

    @Override  //override to check by the value of int[]
    public boolean contains(Object o) {

        for (int[] a : this) {
            if(Arrays.equals(a, (int[]) o)) {
                return true;
            }
        }

        return false;
    }
}

解决方案很长,但不是很复杂。它需要仔细研究 我希望你会发现它有用。

答案 1 :(得分:1)

这里有一个我发现很清楚的相关问题,

MVC (model-view-controller) - can it be explained in simple terms?

MVC用于定义不同“代码”的角色。它类似于一个分层结构,应用于你的代码我建议除以:

  • 模型:搜索邻居的方法,路径以及属于绘制网格的创建部分的所有内容。
  • 控制器:用户与之交互的方法以及稍后将调用模型方法的方法。
  • 查看:打印/打印给用户的所有内容。