实施MVC模型 [英] Implementing the MVC model

查看:73
本文介绍了实施MVC模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Whenever I need help here on SO, I'm asked to post code which follows the MVC model. So went online, read some subject regarding the model but still can't yet understand properly this concept. With the below code for example, I'm trying to adapt it to the MVC model. Does anyone have an idea how to achieve this?

下面的代码绘制2D阵列网格,在单元格内部绘制椭圆形,搜索单元格的邻居,找到通过单元格的路径,然后绘制路径中所有单元格经过的线.

The codes below draw a 2D array grid, paint oval inside cells, search for cells' neighbors, find a path through cells then draw lines passing by all cell within the path.

它包括测试用例,以帮助您更好地了解其工作原理.

It includes test cases to help you better understand how it works.

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;
    }
}

推荐答案

我的答案基于

My answer is based on the MCV model suggested by Hovercraft Full Of Eels in this post.
I made an effort to simplify it a little, added some comments, and adapted it to your code.
I also added path finding calculation.
The code contains 7 classes. I had each class in a separate file, all live in the same folder :


主类

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();
    }
}

路径类以处理路径查找(仍需要进行一些调试)

Path class to handle path finding (still needs some debugging)

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;
    }
}

解决方案很长,但不是很复杂.它确实需要仔细研究.
希望对您有所帮助.

The solution is long, but not very complex. It does need careful studying.
I hope you'll find it helpful.

这篇关于实施MVC模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆