@Override public void surfaceCreated(SurfaceHolder holder) { if (mg == null) { // Grid creation (width and height) mg = new MondrianGrid(getWidth(), getHeight()); // Minimum distance between lines (in mm) final int REJECT_DISTANCE = 7; // Minimum distance between lines (in pixels) int min = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_MM, REJECT_DISTANCE, getResources().getDisplayMetrics()); int rejection = getWidth() / 10; if (rejection < min) { rejection = min; } mg.setRejectionDistance(rejection, rejection); // Computation of the grid mg.computeMondrian(GameActivity.MIN_LINES); // Computation of initially colored shapes randomlyColorShapes(0, GameActivity.MAX_COLOURED, MondrianGrid.RANDOM); // Surface is created -> start drawing drawing = true; } }
/** To clear the colored shapes. */ public void clearColoredShapes() { this.surface_painted = 0; background = getResources().getColor(R.color.mondrian_background); mg.clearShapes(); if (adjacent != null) { adjacent.clear(); } }
/** * Checks whether or not a shape has already been selected. * * @param x x coordinate of the selected pixel. * @param y y coordinate of the selected pixel. * @return True if the selected shape has not already been selected. */ private boolean isAvailable(int x, int y) { if (mg.getShapes().isEmpty()) { return true; } else { for (Map.Entry<Rect, Integer> e : mg.getShapes().entrySet()) { if (e.getKey().contains(x, y)) { return false; } } } return true; }
@Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: if (isAvailable(x, y) && background != DEFAULT_BACKGROUND && !game.isOk() && !game.isOver() && !game.isOnPause()) { // selected shape Rect selected = getSelectedShape(x, y); if (selected != null) { // save the map shape -> color mg.putShape(selected, background); // add color in the set chosenColors.add(background); // compute the painted area surface_painted += selected.width() * selected.height(); // true is the game is over boolean isOver = isAdjacentShapesWithSameColor(selected, background); if (isOver) { adjacent = getAdjacentShapesWithSameColor(selected, background); adjacent.add(selected); game.gameOver(); } else if (surface_painted < getWidth() * getHeight()) { game.updateScore(computeScore()); } // the entire surface is painted else if (surface_painted == getWidth() * getHeight()) { game.increaseGridNumber(); game.updateScore(computeScore()); game.gameSuccess(); } } } break; } return true; }
/** * Returns the Rect area containing the selected pixel * * @param x x-coordinate of the selected pixel * @param y y-coordinate of the selected pixel * @return Rectangle */ public Rect getSelectedShape(int x, int y) { if (!isOnEdge(x, y)) { List<Point> intersections_y = new ArrayList<>(); List<Point> intersections_x = new ArrayList<>(); intersections_y.clear(); intersections_x.clear(); int index_x, index_y; intersections_y = mg.findIntersection(new Line(new Point(x, 0), new Point(x, mg.getHeight()))); intersections_y.add(new Point(x, y)); intersections_x = mg.findIntersection(new Line(new Point(0, y), new Point(mg.getWidth(), y))); intersections_x.add(new Point(x, y)); int[] values_y = new int[intersections_y.size()]; int[] values_x = new int[intersections_x.size()]; for (int j = 0; j < intersections_y.size(); j++) { values_y[j] = intersections_y.get(j).y; } for (int j = 0; j < intersections_x.size(); j++) { values_x[j] = intersections_x.get(j).x; } Arrays.sort(values_x); Arrays.sort(values_y); index_x = Arrays.binarySearch(values_x, x); index_y = Arrays.binarySearch(values_y, y); intersections_y.clear(); intersections_x.clear(); return new Rect( values_x[index_x - 1], values_y[index_y - 1], values_x[index_x + 1], values_y[index_y + 1]); } return null; }
/** * To check if a given point is on the lines defining the grid * * @param x x-coordinate of the selected pixel * @param y y-coordinate of the selected pixel * @return Boolean */ private boolean isOnEdge(int x, int y) { Point selectedPoint = new Point(x, y); List<Line> lines = mg.getLines(); for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { Line line = lines.get(i); if (line.contains(selectedPoint)) { return true; } } return false; }
@Override public void onDraw(Canvas canvas) { super.onDraw(canvas); // If the game is paused we mask the game view if (hide) { setBackgroundColor(getResources().getColor(R.color.black)); } // Otherwise if the game is pending else { setBackgroundResource(R.drawable.grid_background); // Fill the shapes if (mg != null && !mg.getShapes().isEmpty()) { for (Map.Entry<Rect, Integer> e : mg.getShapes().entrySet()) { fill.setColor(e.getValue()); canvas.drawRect(e.getKey(), fill); } } // If you lose (there is at least one adjacent shape with the same color) if (adjacent != null && !adjacent.isEmpty()) { for (Rect rect : adjacent) { canvas.drawRect(rect, striped); } } // Stroke if (mg != null && !mg.getLines().isEmpty()) { for (Line line : mg.getLines()) { canvas.drawLine( line.getStart().x, line.getStart().y, line.getEnd().x, line.getEnd().y, stroke); } } } }
/** * Selects and colors random shapes. * * @param min Minimum number of pre-painted shapes. * @param max Maximum number of pre-painted shapes. */ public void randomlyColorShapes(int min, int max, Random rand) { // Number of pre-colored shapes int nb_shapes = Utility.randInt(min, max, rand); int color = 0; int x, y, col; int cpt = 0; Rect current; if (nb_shapes > 0) { while (cpt < nb_shapes) { x = Utility.randInt(this.getLeft() + 1, this.getWidth() - 1, rand); y = Utility.randInt(this.getTop() + 1, this.getHeight() - 1, rand); current = getSelectedShape(x, y); col = Utility.randInt(0, 3, rand); switch (col) { case 0: color = getResources().getColor(R.color.red); break; case 1: color = getResources().getColor(R.color.blue); break; case 2: color = getResources().getColor(R.color.yellow); break; case 3: color = getResources().getColor(R.color.white); break; } if (current != null && isAvailable(x, y) && !isAdjacentShapesWithSameColor(current, color)) { initiallyColoredShapes.put(current, color); mg.putShape(current, color); surface_painted += current.width() * current.height(); cpt++; } } } }
/** * To have a list of adjacent shapes with the same color (game over case) * * @param current Selected area * @param color Color of the selected area * @return A list of adjacent shapes with the same color */ private List<Rect> getAdjacentShapesWithSameColor(Rect current, int color) { List<Rect> adjacent = null; if (!mg.getShapes().isEmpty()) { adjacent = new ArrayList<>(); adjacent.clear(); for (Map.Entry<Rect, Integer> entry : mg.getShapes().entrySet()) { // one shape on top of another if (current.bottom == entry.getKey().top || current.top == entry.getKey().bottom) { if (current.left < entry.getKey().right && current.left >= entry.getKey().left && current.right >= entry.getKey().right) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } else if (current.left >= entry.getKey().left && current.left < entry.getKey().right && current.right > entry.getKey().left && current.right <= entry.getKey().right) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } else if (current.left <= entry.getKey().left && current.right > entry.getKey().left && current.right <= entry.getKey().right) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } else if (current.left < entry.getKey().left && current.right > entry.getKey().right) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } } // One shape on the side of another else if (current.right == entry.getKey().left || current.left == entry.getKey().right) { if (current.bottom <= entry.getKey().bottom && current.bottom > entry.getKey().top && current.top <= entry.getKey().top) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } else if (current.bottom > entry.getKey().top && current.bottom <= entry.getKey().bottom && current.top >= entry.getKey().top && current.top < entry.getKey().bottom) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } else if (current.top < entry.getKey().bottom && current.top >= entry.getKey().top && current.bottom >= entry.getKey().bottom) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } else if (current.top < entry.getKey().top && current.bottom > entry.getKey().bottom) { if (color == entry.getValue()) { adjacent.add(entry.getKey()); } } } } } return adjacent; }
/** * To know if a selected area can be painted with a given color * * @param current Selected area * @param color Color of the selected area * @return True if an adjacent area is already painted with the same color */ private boolean isAdjacentShapesWithSameColor(Rect current, int color) { if (!mg.getShapes().isEmpty()) { for (Map.Entry<Rect, Integer> entry : mg.getShapes().entrySet()) { // one shape on top of another if (current.bottom == entry.getKey().top || current.top == entry.getKey().bottom) { if (current.left < entry.getKey().right && current.left >= entry.getKey().left && current.right >= entry.getKey().right) { if (color == entry.getValue()) { return true; } } else if (current.left >= entry.getKey().left && current.left < entry.getKey().right && current.right > entry.getKey().left && current.right <= entry.getKey().right) { if (color == entry.getValue()) { return true; } } else if (current.left <= entry.getKey().left && current.right > entry.getKey().left && current.right <= entry.getKey().right) { if (color == entry.getValue()) { return true; } } else if (current.left < entry.getKey().left && current.right > entry.getKey().right) { if (color == entry.getValue()) { return true; } } } // One shape on the side of another else if (current.right == entry.getKey().left || current.left == entry.getKey().right) { if (current.bottom <= entry.getKey().bottom && current.bottom > entry.getKey().top && current.top <= entry.getKey().top) { if (color == entry.getValue()) { return true; } } else if (current.bottom > entry.getKey().top && current.bottom <= entry.getKey().bottom && current.top >= entry.getKey().top && current.top < entry.getKey().bottom) { if (color == entry.getValue()) { return true; } } else if (current.top < entry.getKey().bottom && current.top >= entry.getKey().top && current.bottom >= entry.getKey().bottom) { if (color == entry.getValue()) { return true; } } else if (current.top < entry.getKey().top && current.bottom > entry.getKey().bottom) { if (color == entry.getValue()) { return true; } } } } } return false; }