Reputation: 1709
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?
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;
}
}
Upvotes: 0
Views: 209
Reputation: 84
Here there is a related question I found very clear,
MVC (model-view-controller) - can it be explained in simple terms?
The MVC is used to define the roles of different "bolcks" of code. It's similar to a layered structure, applied to your code I would suggest to divide as:
Upvotes: 1
Reputation: 18792
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 :
Main class
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);
});
}
}
Control class
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();
}
});
}
}
}
Model class
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();
}
}
View class
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;
}
}
Token enum as in OP
public enum Token {
VIDE, CERCLE_BLEU, CERCLE_ROUGE
}
A simple collection override
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.
Upvotes: 3