Logo Studenta

ALED_LAB2

Esta es una vista previa del archivo. Inicie sesión para ver el archivo original

ALED-lab2 (1).zip
ALED-lab2/.classpath
 
	 
	 
	 
ALED-lab2/.project
 
	 ALED-lab2
	 
	 
	
	 
		 
			 org.eclipse.jdt.core.javabuilder
			 
			
		
	
	 
		 org.eclipse.jdt.core.javanature
	
ALED-lab2/.settings/org.eclipse.jdt.core.prefs
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
ALED-lab2/src/es/upm/dit/aled/lab2/Laberinto.java
ALED-lab2/src/es/upm/dit/aled/lab2/Laberinto.java
package es.upm.dit.aled.lab2;
import java.awt.Font;
public class Laberinto {
    protected int N; // Tamano alto y ancho del laberinto
    // norte, sur este y oeste nos dicen cuando hay paredes o no alrededor de una posicion
    protected boolean[][] norte;
    protected boolean[][] este;
    protected boolean[][] sur;
    protected boolean[][] oeste;
    // visitado nos dice cuando hemos pasado por una posicion
    protected boolean[][] visitado;
    // encontrado: hemos llegado al punto central
    protected boolean encontrado = false;
    protected double radio=StdDraw.getPenRadius();
    /**
     * Crea un nuevo laberinto
     * 
     * @param N tamano del laberinto
     */
    public Laberinto(int N) {
        this.N = N;
        StdDraw.setCanvasSize(700,700);
        StdDraw.setXscale(0, N+2);
        StdDraw.setYscale(0, N+2);
        init();
        generar();
    }
    private void init() {
        // todas las posiciones del marco exterior marcadas como visitadas
        visitado = new boolean[N+2][N+2];
        for (int x = 0; x < N+2; x++) visitado[x][0] = visitado[x][N+1] = true;
        for (int y = 0; y < N+2; y++) visitado[0][y] = visitado[N+1][y] = true;
        // todas las paredes levantadas
        norte = new boolean[N+2][N+2];
        este  = new boolean[N+2][N+2];
        sur = new boolean[N+2][N+2];
        oeste  = new boolean[N+2][N+2];
        for (int x = 0; x < N+2; x++)
            for (int y = 0; y < N+2; y++)
                norte[x][y] = este[x][y] = sur[x][y] = oeste[x][y] = true;
    }
    // generar el laberinto
    private void generar(int x, int y) {
        visitado[x][y] = true;
        // mientras tengamos una posicion junto a esta que no este visitada
        while (!visitado[x][y+1] || !visitado[x+1][y] || !visitado[x][y-1] || !visitado[x-1][y]) {
            // elegimos una posicion cualquiera
            while (true) {
                double r = Math.random();
                if (r < 0.25 && !visitado[x][y+1]) {
                    norte[x][y] = sur[x][y+1] = false;
                    generar(x, y + 1);
                    break;
                }
                else if (r >= 0.25 && r < 0.50 && !visitado[x+1][y]) {
                    este[x][y] = oeste[x+1][y] = false;
                    generar(x+1, y);
                    break;
                }
                else if (r >= 0.5 && r < 0.75 && !visitado[x][y-1]) {
                    sur[x][y] = norte[x][y-1] = false;
                    generar(x, y-1);
                    break;
                }
                else if (r >= 0.75 && r < 1.00 && !visitado[x-1][y]) {
                    oeste[x][y] = este[x-1][y] = false;
                    generar(x-1, y);
                    break;
                }
            }
        }
    }
    /**
     * Generamos un laberinto, empezamos a generar por la posicion izquierda y abajo
     */
    protected void generar() {
        generar(1, 1);
    }
    // resolvemos buscado la primera solucion que encontremos
    private int resolver(int x, int y, int pasos) {
            // TODO
        return 0;
    }
    /**
     * Resolver el laberinto empezando en la primera posicion: abajo a la izquierda
     * @return numero de pasos dados
     */
    public int resolver() {
        for (int x = 1; x <= N; x++)
            for (int y = 1; y <= N; y++)
                visitado[x][y] = false;
        encontrado = false;
        return resolver(1, 1, 1);
        // StdDraw.show(0);
    }
    /**
     * Dibuja el laberinto
     */
    public void dibuja() {
            StdDraw.clear();
            StdDraw.setPenRadius(radio);
        StdDraw.setPenColor(StdDraw.RED);
        StdDraw.filledCircle(Math.round(N/2.0) + 0.5, Math.round(N/2.0) + 0.5, 0.375);
        StdDraw.filledCircle(1.5, 1.5, 0.375);
        StdDraw.setPenColor(StdDraw.BLACK);
        Font f = StdDraw.getFont();
        int size=300/N;
        StdDraw.setFont(new Font(null,0, size > 12 ? 16 : size));
        for (int x = 1; x <= N; x++)
            StdDraw.text(x+0.5, 0, new Integer(x).toString());
        for (int y = 1; y <= N; y++)
            StdDraw.text(0, y+0.5, new Integer(y).toString());
        StdDraw.setFont(f);
        for (int x = 1; x <= N; x++) {
            for (int y = 1; y <= N; y++) {
                if (sur[x][y]) StdDraw.line(x, y, x + 1, y);
                if (norte[x][y]) StdDraw.line(x, y + 1, x + 1, y + 1);
                if (oeste[x][y])  StdDraw.line(x, y, x, y + 1);
                if (este[x][y])  StdDraw.line(x + 1, y, x + 1, y + 1);
            }
        }
        StdDraw.show(0);
    }
    /**
     * Punto de entrada al programa. Incluye una prueba
     * @param args debe incluir un argumento con el tamano del laberinto
     */
    public static void main(String[] args) {
        int N = Integer.parseInt(args[0]);
        Laberinto laberinto = new Laberinto(N);
        StdDraw.show(0);
        laberinto.dibuja();
        System.out.println("Pasos hasta solucion: "+laberinto.resolver());
    }
}
ALED-lab2/src/es/upm/dit/aled/lab2/LaberintoTodoAccesible.java
ALED-lab2/src/es/upm/dit/aled/lab2/LaberintoTodoAccesible.java
package es.upm.dit.aled.lab2;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
 * Clase para mejorar la generacion de laberintos que se resuelven en Laberinto
 * 
 * @author Miguel A. de Miguel
 *
 * es.upm.dit.aled.lab2.Laberinto
 */
public class LaberintoTodoAccesible extends Laberinto {
    
    /**
     * Constructor para crear un nuevo laberinto. Este constructor inicializa el laberinto y lo genera
     * 
     * @param n numero de filas y columnas del laberinto cuadrado
     */
    public LaberintoTodoAccesible(int n) {
        super(n);
    }
    public boolean compruebaAccesibilidad() {
        // TODO
        return false;
    }
    
    protected void aisla(int x, int y) {
        // TODO
    }
    
    /**
     * Prueba de ejecucion controlando la acesibilidad de todo el laberinto
     * 
     * @param numFilasColumnas tamano del laberinto
     * @return falso si todo el labrinto no es accesible
     */
    public static boolean ejecutaConControlAccesibilidad(int numFilasColumnas) {
        LaberintoTodoAccesible laberinto = new LaberintoTodoAccesible(numFilasColumnas);
        StdDraw.show(0);
        laberinto.dibuja();
        if (!laberinto.compruebaAccesibilidad())
                return false;
        laberinto.resolver();
        return true;
    }
    /**
     * Prueba de ejecucion controlando la acesibilidad de todo el laberinto, y aislando 
     * el punto central
     * 
     * @param numFilasColumnas tamano del labrinto
     * @return
falso si todo el labrinto no es accesible
     */
    public static boolean ejecutaConControlAccesibilidadYAislado(int numFilasColumnas) {
        LaberintoTodoAccesible laberinto = new LaberintoTodoAccesible(numFilasColumnas);
        laberinto.aisla(numFilasColumnas/2,numFilasColumnas/2);
        StdDraw.show(0);
        laberinto.dibuja();
        if (!laberinto.compruebaAccesibilidad())
                return false;
        laberinto.resolver();
        return true;
    }
    /**
     * Punto de entrada al programa
     * 
     * @param args argumentos de la linea de comandos
     */
    public static void main(String[] args) {
        int N = Integer.parseInt(args[0]);
        if (LaberintoTodoAccesible.ejecutaConControlAccesibilidad(N))
            System.out.println("Todas las posiciones son accesibles");
        else System.out.println("Hay posiciones no accesibles");
        /*
        if (LaberintoTodoAccesible.ejecutaConControlAccesibilidadYAislado(N))
            System.out.println("Todas las posiciones son accesibles");
        else System.out.println("Hay posiciones no accesibles");
        */
    }
}
ALED-lab2/src/es/upm/dit/aled/lab2/StdDraw.java
ALED-lab2/src/es/upm/dit/aled/lab2/StdDraw.java
package es.upm.dit.aled.lab2;
/*************************************************************************
 *  Compilation:  javac StdDraw.java
 *  Execution:    java StdDraw
 *
 *  Standard drawing library. This class provides a basic capability for
 *  creating drawings with your programs. It uses a simple graphics model that
 *  allows you to create drawings consisting of points, lines, and curves
 *  in a window on your computer and to save the drawings to a file.
 *
 *  Todo
 *  ----
 *    -  Add support for gradient fill, etc.
 *
 *  Remarks
 *  -------
 *    -  don't use AffineTransform for rescaling since it inverts
 *       images and strings
 *    -  careful using setFont in inner loop within an animation -
 *       it can cause flicker
 *
 *************************************************************************/
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.util.LinkedList;
import java.util.TreeSet;
import javax.imageio.ImageIO;
import javax.swing.*;
/**
 *  <i>Standard draw</i>. This class provides a basic capability for
 *  creating drawings with your programs. It uses a simple graphics model that
 *  allows you to create drawings consisting of points, lines, and curves
 *  in a window on your computer and to save the drawings to a file.
 *  <p>
 *  For additional documentation, see <a href="http://introcs.cs.princeton.edu/15inout">Section 1.5</a> of
 *  <i>Introduction to Programming in Java: An Interdisciplinary Approach</i> by Robert Sedgewick and Kevin Wayne.
 */
public final class StdDraw implements ActionListener, MouseListener, MouseMotionListener, KeyListener {
    // pre-defined colors
    public static final Color BLACK      = Color.BLACK;
    public static final Color BLUE       = Color.BLUE;
    public static final Color CYAN       = Color.CYAN;
    public static final Color DARK_GRAY  = Color.DARK_GRAY;
    public static final Color GRAY       = Color.GRAY;
    public static final Color GREEN      = Color.GREEN;
    public static final Color LIGHT_GRAY = Color.LIGHT_GRAY;
    public static final Color MAGENTA    = Color.MAGENTA;
    public static final Color ORANGE     = Color.ORANGE;
    public static final Color PINK       = Color.PINK;
    public static final Color RED        = Color.RED;
    public static final Color WHITE      = Color.WHITE;
    public static final Color YELLOW     = Color.YELLOW;
    /**
     * Shade of blue used in Introduction to Programming in Java.
     * It is Pantone 300U. The RGB values are approximately (9, 90, 166).
     */
    public static final Color BOOK_BLUE       = new Color(  9,  90, 166);
    public static final Color BOOK_LIGHT_BLUE = new Color(103, 198, 243);
    /**
     * Shade of red used in Algorithms 4th edition.
     * It is Pantone 1805U. The RGB values are approximately (150, 35, 31).
     */
    public static final Color BOOK_RED = new Color(150, 35, 31);
    // default colors
    private static final Color DEFAULT_PEN_COLOR   = BLACK;
    private static final Color DEFAULT_CLEAR_COLOR = WHITE;
    // current pen color
    private static Color penColor;
    // default canvas size is DEFAULT_SIZE-by-DEFAULT_SIZE
    private static final int DEFAULT_SIZE = 512;
    private static int width  = DEFAULT_SIZE;
    private static int height = DEFAULT_SIZE;
    // default pen radius
    private static final double DEFAULT_PEN_RADIUS = 0.002;
    // current pen radius
    private static double penRadius;
    // show we draw immediately or wait until next show?
    private static boolean defer = false;
    // boundary of drawing canvas, 5% border
    private static final double BORDER = 0.05;
    private static final double DEFAULT_XMIN = 0.0;
    private static final double DEFAULT_XMAX = 1.0;
    private static final double DEFAULT_YMIN = 0.0;
    private static final double DEFAULT_YMAX = 1.0;
    private static double xmin, ymin, xmax, ymax;
    // for synchronization
    private static Object mouseLock = new Object();
    private static Object keyLock = new Object();
    // default font
    private static final Font DEFAULT_FONT = new Font("SansSerif", Font.PLAIN, 16);
    // current font
    private static Font font;
    // double buffered graphics
    private static BufferedImage offscreenImage, onscreenImage;
    private static Graphics2D offscreen, onscreen;
    // singleton for callbacks: avoids generation of extra .class files
    private static StdDraw std = new StdDraw();
    // the frame for drawing to the screen
    private static JFrame frame;
    // mouse state
    private static boolean mousePressed = false;
    private static double mouseX = 0;
    private static double mouseY = 0;
    // queue of typed key characters
    private static LinkedList<Character> keysTyped = new LinkedList<Character>();
    // set of key codes currently pressed down
    private static TreeSet<Integer> keysDown = new TreeSet<Integer>();
  
    // singleton pattern: client can't instantiate
    private StdDraw() { }
    // static initializer
    static { init(); }
    /**
     * Set the window size to the default size 512-by-512 pixels.
     */
    public static void setCanvasSize() {
        setCanvasSize(DEFAULT_SIZE, DEFAULT_SIZE);
    }
    /**
     * Set the window size to w-by-h pixels.
     *
     * @param w the width as a number of pixels
     * @param h the height as a number of pixels
     * @throws a IllegalArgumentException if the width or height is 0 or negative
     */
    public static void setCanvasSize(int w, int h) {
        if (w < 1 || h < 1) throw new IllegalArgumentException("width and height must be positive");
        width = w;
        height = h;
        init();
    }
    // init
    private static void init() {
        if (frame != null) frame.setVisible(false);
        try {
                frame = new JFrame();
        } catch (Exception e) {
                defer=true;
        }
        offscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        onscreenImage  = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        offscreen = offscreenImage.createGraphics();
        onscreen  = onscreenImage.createGraphics();
        setXscale();
        setYscale();
        offscreen.setColor(DEFAULT_CLEAR_COLOR);
        offscreen.fillRect(0,
0, width, height);
        setPenColor();
        setPenRadius();
        setFont();
        clear();
        // add antialiasing
        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
                                                  RenderingHints.VALUE_ANTIALIAS_ON);
        hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        offscreen.addRenderingHints(hints);
        // frame stuff
        ImageIcon icon = new ImageIcon(onscreenImage);
        JLabel draw = new JLabel(icon);
        draw.addMouseListener(std);
        draw.addMouseMotionListener(std);
        if (frame != null) {
            frame.setContentPane(draw);
            frame.addKeyListener(std);    // JLabel cannot get keyboard focus
            frame.setResizable(false);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);            // closes all windows
            // frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);      // closes only current window
            frame.setTitle("Standard Draw");
            frame.setJMenuBar(createMenuBar());
            frame.pack();
            frame.requestFocusInWindow();
            frame.setVisible(true);
        }
    }
    // create the menu bar (changed to private)
    private static JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("File");
        menuBar.add(menu);
        JMenuItem menuItem1 = new JMenuItem(" Save...   ");
        menuItem1.addActionListener(std);
        menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
                                Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        menu.add(menuItem1);
        return menuBar;
    }
   /*************************************************************************
    *  User and screen coordinate systems
    *************************************************************************/
    /**
     * Set the x-scale to be the default (between 0.0 and 1.0).
     */
    public static void setXscale() { setXscale(DEFAULT_XMIN, DEFAULT_XMAX); }
    /**
     * Set the y-scale to be the default (between 0.0 and 1.0).
     */
    public static void setYscale() { setYscale(DEFAULT_YMIN, DEFAULT_YMAX); }
    /**
     * Set the x-scale (a 10% border is added to the values)
     * @param min the minimum value of the x-scale
     * @param max the maximum value of the x-scale
     */
    public static void setXscale(double min, double max) {
        double size = max - min;
        synchronized (mouseLock) {
            xmin = min - BORDER * size;
            xmax = max + BORDER * size;
        }
    }
    /**
     * Set the y-scale (a 10% border is added to the values).
     * @param min the minimum value of the y-scale
     * @param max the maximum value of the y-scale
     */
    public static void setYscale(double min, double max) {
        double size = max - min;
        synchronized (mouseLock) {
            ymin = min - BORDER * size;
            ymax = max + BORDER * size;
        }
    }
    /**
     * Set the x-scale and y-scale (a 10% border is added to the values)
     * @param min the minimum value of the x- and y-scales
     * @param max the maximum value of the x- and y-scales
     */
    public static void setScale(double min, double max) {
        double size = max - min;
        synchronized (mouseLock) {
            xmin = min - BORDER * size;
            xmax = max + BORDER * size;
            ymin = min - BORDER * size;
            ymax = max + BORDER * size;
        }
    }
    // helper functions that scale from user coordinates to screen coordinates and back
    private static double  scaleX(double x) { return width  * (x - xmin) / (xmax - xmin); }
    private static double  scaleY(double y) { return height * (ymax - y) / (ymax - ymin); }
    private static double factorX(double w) { return w * width  / Math.abs(xmax - xmin);  }
    private static double factorY(double h) { return h * height / Math.abs(ymax - ymin);  }
    private static double   userX(double x) { return xmin + x * (xmax - xmin) / width;    }
    private static double   userY(double y) { return ymax - y * (ymax - ymin) / height;   }
    /**
     * Clear the screen to the default color (white).
     */
    public static void clear() { clear(DEFAULT_CLEAR_COLOR); }
    /**
     * Clear the screen to the given color.
     * @param color the Color to make the background
     */
    public static void clear(Color color) {
        offscreen.setColor(color);
        offscreen.fillRect(0, 0, width, height);
        offscreen.setColor(penColor);
        draw();
    }
    /**
     * Get the current pen radius.
     */
    public static double getPenRadius() { return penRadius; }
    /**
     * Set the pen size to the default (.002).
     */
    public static void setPenRadius() { setPenRadius(DEFAULT_PEN_RADIUS); }
    /**
     * Set the radius of the pen to the given size.
     * @param r the radius of the pen
     * @throws IllegalArgumentException if r is negative
     */
    public static void setPenRadius(double r) {
        if (r < 0) throw new IllegalArgumentException("pen radius must be nonnegative");
        penRadius = r;
        float scaledPenRadius = (float) (r * DEFAULT_SIZE);
        BasicStroke stroke = new BasicStroke(scaledPenRadius, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        // BasicStroke stroke = new BasicStroke(scaledPenRadius);
        offscreen.setStroke(stroke);
    }
    /**
     * Get the current pen color.
     */
    public static Color getPenColor() { return penColor; }
    /**
     * Set the pen color to the default color (black).
     */
    public static void setPenColor() { setPenColor(DEFAULT_PEN_COLOR); }
    /**
     * Set the pen color to the given color. The available pen colors are
     * BLACK, BLUE, CYAN, DARK_GRAY, GRAY, GREEN, LIGHT_GRAY, MAGENTA,
     * ORANGE, PINK, RED, WHITE, and YELLOW.
     * @param color the Color to make the pen
     */
    public static void setPenColor(Color color) {
        penColor = color;
        offscreen.setColor(penColor);
    }
    /**
     * Set the pen color to the given RGB color.
     * @param red the amount of red (between 0 and 255)
     * @param green the amount of green (between 0 and 255)
     * @param blue the amount of blue (between 0 and 255)
     * @throws IllegalArgumentException if the amount of red, green, or blue are outside prescribed range
     */
    public static void setPenColor(int red, int green, int blue) {
        if (red   < 0 || red   >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255");
        if (green < 0 || green >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255");
        if (blue  < 0 || blue  >= 256) throw new IllegalArgumentException("amount of red must be between 0 and 255");
        setPenColor(new Color(red, green, blue));
    }
    /**
     * Get the current font.
     */
    public static Font getFont() { return font; }
    /**
     * Set the font to the default font (sans serif, 16 point).
     */
    public static void setFont() { setFont(DEFAULT_FONT); }
    /**
     * Set the font to the given value.
     * @param f the font to make text
     */
    public static void setFont(Font f) { font = f; }
   /*************************************************************************
    *  Drawing geometric shapes.
    *************************************************************************/
    /**
     * Draw a line from (x0, y0) to (x1, y1).
     * @param x0 the x-coordinate
of the starting point
     * @param y0 the y-coordinate of the starting point
     * @param x1 the x-coordinate of the destination point
     * @param y1 the y-coordinate of the destination point
     */
    public static void line(double x0, double y0, double x1, double y1) {
        offscreen.draw(new Line2D.Double(scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1)));
        draw();
    }
    /**
     * Draw one pixel at (x, y).
     * @param x the x-coordinate of the pixel
     * @param y the y-coordinate of the pixel
     */
    private static void pixel(double x, double y) {
        offscreen.fillRect((int) Math.round(scaleX(x)), (int) Math.round(scaleY(y)), 1, 1);
    }
    /**
     * Draw a point at (x, y).
     * @param x the x-coordinate of the point
     * @param y the y-coordinate of the point
     */
    public static void point(double x, double y) {
        double xs = scaleX(x);
        double ys = scaleY(y);
        double r = penRadius;
        float scaledPenRadius = (float) (r * DEFAULT_SIZE);
        // double ws = factorX(2*r);
        // double hs = factorY(2*r);
        // if (ws <= 1 && hs <= 1) pixel(x, y);
        if (scaledPenRadius <= 1) pixel(x, y);
        else offscreen.fill(new Ellipse2D.Double(xs - scaledPenRadius/2, ys - scaledPenRadius/2,
                                                 scaledPenRadius, scaledPenRadius));
        draw();
    }
    /**
     * Draw a circle of radius r, centered on (x, y).
     * @param x the x-coordinate of the center of the circle
     * @param y the y-coordinate of the center of the circle
     * @param r the radius of the circle
     * @throws IllegalArgumentException if the radius of the circle is negative
     */
    public static void circle(double x, double y, double r) {
        if (r < 0) throw new IllegalArgumentException("circle radius must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw filled circle of radius r, centered on (x, y).
     * @param x the x-coordinate of the center of the circle
     * @param y the y-coordinate of the center of the circle
     * @param r the radius of the circle
     * @throws IllegalArgumentException if the radius of the circle is negative
     */
    public static void filledCircle(double x, double y, double r) {
        if (r < 0) throw new IllegalArgumentException("circle radius must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw an ellipse with given semimajor and semiminor axes, centered on (x, y).
     * @param x the x-coordinate of the center of the ellipse
     * @param y the y-coordinate of the center of the ellipse
     * @param semiMajorAxis is the semimajor axis of the ellipse
     * @param semiMinorAxis is the semiminor axis of the ellipse
     * @throws IllegalArgumentException if either of the axes are negative
     */
    public static void ellipse(double x, double y, double semiMajorAxis, double semiMinorAxis) {
        if (semiMajorAxis < 0) throw new IllegalArgumentException("ellipse semimajor axis must be nonnegative");
        if (semiMinorAxis < 0) throw new IllegalArgumentException("ellipse semiminor axis must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*semiMajorAxis);
        double hs = factorY(2*semiMinorAxis);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw an ellipse with given semimajor and semiminor axes, centered on (x, y).
     * @param x the x-coordinate of the center of the ellipse
     * @param y the y-coordinate of the center of the ellipse
     * @param semiMajorAxis is the semimajor axis of the ellipse
     * @param semiMinorAxis is the semiminor axis of the ellipse
     * @throws IllegalArgumentException if either of the axes are negative
     */
    public static void filledEllipse(double x, double y, double semiMajorAxis, double semiMinorAxis) {
        if (semiMajorAxis < 0) throw new IllegalArgumentException("ellipse semimajor axis must be nonnegative");
        if (semiMinorAxis < 0) throw new IllegalArgumentException("ellipse semiminor axis must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*semiMajorAxis);
        double hs = factorY(2*semiMinorAxis);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw an arc of radius r, centered on (x, y), from angle1 to angle2 (in degrees).
     * @param x the x-coordinate of the center of the circle
     * @param y the y-coordinate of the center of the circle
     * @param r the radius of the circle
     * @param angle1 the starting angle. 0 would mean an arc beginning at 3 o'clock.
     * @param angle2 the angle at the end of the arc. For example, if
     *        you want a 90 degree arc, then angle2 should be angle1 + 90.
     * @throws IllegalArgumentException if the radius of the circle is negative
     */
    public static void arc(double x, double y, double r, double angle1, double angle2) {
        if (r < 0) throw new IllegalArgumentException("arc radius must be nonnegative");
        while (angle2 < angle1) angle2 += 360;
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.draw(new Arc2D.Double(xs - ws/2, ys - hs/2, ws, hs, angle1, angle2 - angle1, Arc2D.OPEN));
        draw();
    }
    /**
     * Draw a square of side length 2r, centered on (x, y).
     * @param x the x-coordinate of the center of the square
     * @param y the y-coordinate of the center of the square
     * @param r radius is half the length of any side of the square
     * @throws IllegalArgumentException if r is negative
     */
    public static void square(double x, double y, double r) {
        if (r < 0) throw new IllegalArgumentException("square side length must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw a filled square of side length 2r, centered on (x, y).
     * @param x the x-coordinate of the center of the square
     * @param y the y-coordinate of the center of the square
     * @param r radius is half the length of any side of the square
     * @throws IllegalArgumentException if r is negative
     */
    public static void filledSquare(double x, double y, double r) {
        if (r < 0) throw new IllegalArgumentException("square side length must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*r);
        double hs = factorY(2*r);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw
a rectangle of given half width and half height, centered on (x, y).
     * @param x the x-coordinate of the center of the rectangle
     * @param y the y-coordinate of the center of the rectangle
     * @param halfWidth is half the width of the rectangle
     * @param halfHeight is half the height of the rectangle
     * @throws IllegalArgumentException if halfWidth or halfHeight is negative
     */
    public static void rectangle(double x, double y, double halfWidth, double halfHeight) {
        if (halfWidth  < 0) throw new IllegalArgumentException("half width must be nonnegative");
        if (halfHeight < 0) throw new IllegalArgumentException("half height must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*halfWidth);
        double hs = factorY(2*halfHeight);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw a filled rectangle of given half width and half height, centered on (x, y).
     * @param x the x-coordinate of the center of the rectangle
     * @param y the y-coordinate of the center of the rectangle
     * @param halfWidth is half the width of the rectangle
     * @param halfHeight is half the height of the rectangle
     * @throws IllegalArgumentException if halfWidth or halfHeight is negative
     */
    public static void filledRectangle(double x, double y, double halfWidth, double halfHeight) {
        if (halfWidth  < 0) throw new IllegalArgumentException("half width must be nonnegative");
        if (halfHeight < 0) throw new IllegalArgumentException("half height must be nonnegative");
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(2*halfWidth);
        double hs = factorY(2*halfHeight);
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));
        draw();
    }
    /**
     * Draw a polygon with the given (x[i], y[i]) coordinates.
     * @param x an array of all the x-coordindates of the polygon
     * @param y an array of all the y-coordindates of the polygon
     */
    public static void polygon(double[] x, double[] y) {
        int N = x.length;
        GeneralPath path = new GeneralPath();
        path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));
        for (int i = 0; i < N; i++)
            path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));
        path.closePath();
        offscreen.draw(path);
        draw();
    }
    /**
     * Draw a filled polygon with the given (x[i], y[i]) coordinates.
     * @param x an array of all the x-coordindates of the polygon
     * @param y an array of all the y-coordindates of the polygon
     */
    public static void filledPolygon(double[] x, double[] y) {
        int N = x.length;
        GeneralPath path = new GeneralPath();
        path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));
        for (int i = 0; i < N; i++)
            path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));
        path.closePath();
        offscreen.fill(path);
        draw();
    }
   /*************************************************************************
    *  Drawing images.
    *************************************************************************/
    // get an image from the given filename
    private static Image getImage(String filename) {
        // to read from file
        ImageIcon icon = new ImageIcon(filename);
        // try to read from URL
        if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {
            try {
                URL url = new URL(filename);
                icon = new ImageIcon(url);
            } catch (Exception e) { /* not a url */ }
        }
        // in case file is inside a .jar
        if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {
            URL url = StdDraw.class.getResource(filename);
            if (url == null) throw new IllegalArgumentException("image " + filename + " not found");
            icon = new ImageIcon(url);
        }
        return icon.getImage();
    }
    /**
     * Draw picture (gif, jpg, or png) centered on (x, y).
     * @param x the center x-coordinate of the image
     * @param y the center y-coordinate of the image
     * @param s the name of the image/picture, e.g., "ball.gif"
     * @throws IllegalArgumentException if the image is corrupt
     */
    public static void picture(double x, double y, String s) {
        Image image = getImage(s);
        double xs = scaleX(x);
        double ys = scaleY(y);
        int ws = image.getWidth(null);
        int hs = image.getHeight(null);
        if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
        offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);
        draw();
    }
    /**
     * Draw picture (gif, jpg, or png) centered on (x, y),
     * rotated given number of degrees
     * @param x the center x-coordinate of the image
     * @param y the center y-coordinate of the image
     * @param s the name of the image/picture, e.g., "ball.gif"
     * @param degrees is the number of degrees to rotate counterclockwise
     * @throws IllegalArgumentException if the image is corrupt
     */
    public static void picture(double x, double y, String s, double degrees) {
        Image image = getImage(s);
        double xs = scaleX(x);
        double ys = scaleY(y);
        int ws = image.getWidth(null);
        int hs = image.getHeight(null);
        if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
        offscreen.rotate(Math.toRadians(-degrees), xs, ys);
        offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);
        offscreen.rotate(Math.toRadians(+degrees), xs, ys);
        draw();
    }
    /**
     * Draw picture (gif, jpg, or png) centered on (x, y), rescaled to w-by-h.
     * @param x the center x coordinate of the image
     * @param y the center y coordinate of the image
     * @param s the name of the image/picture, e.g., "ball.gif"
     * @param w the width of the image
     * @param h the height of the image
     * @throws IllegalArgumentException if the width height are negative
     * @throws IllegalArgumentException if the image is corrupt
     */
    public static void picture(double x, double y, String s, double w, double h) {
        Image image = getImage(s);
        double xs = scaleX(x);
        double ys = scaleY(y);
        if (w < 0) throw new IllegalArgumentException("width is negative: " + w);
        if (h < 0) throw new IllegalArgumentException("height is negative: " + h);
        double ws = factorX(w);
        double hs = factorY(h);
        if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
        if (ws <= 1 && hs <= 1) pixel(x, y);
        else {
            offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),
                                       (int) Math.round(ys - hs/2.0),
                                       (int) Math.round(ws),
                                       (int) Math.round(hs), null);
        }
        draw();
    }
    /**
     * Draw picture (gif, jpg, or png) centered on (x, y), rotated
     * given number of degrees, rescaled to w-by-h.
     * @param x the center x-coordinate of the image
     * @param y the center y-coordinate of the image
     * @param s the name of the image/picture, e.g., "ball.gif"
     * @param
w the width of the image
     * @param h the height of the image
     * @param degrees is the number of degrees to rotate counterclockwise
     * @throws IllegalArgumentException if the image is corrupt
     */
    public static void picture(double x, double y, String s, double w, double h, double degrees) {
        Image image = getImage(s);
        double xs = scaleX(x);
        double ys = scaleY(y);
        double ws = factorX(w);
        double hs = factorY(h);
        if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + s + " is corrupt");
        if (ws <= 1 && hs <= 1) pixel(x, y);
        offscreen.rotate(Math.toRadians(-degrees), xs, ys);
        offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),
                                   (int) Math.round(ys - hs/2.0),
                                   (int) Math.round(ws),
                                   (int) Math.round(hs), null);
        offscreen.rotate(Math.toRadians(+degrees), xs, ys);
        draw();
    }
   /*************************************************************************
    *  Drawing text.
    *************************************************************************/
    /**
     * Write the given text string in the current font, centered on (x, y).
     * @param x the center x-coordinate of the text
     * @param y the center y-coordinate of the text
     * @param s the text
     */
    public static void text(double x, double y, String s) {
        offscreen.setFont(font);
        FontMetrics metrics = offscreen.getFontMetrics();
        double xs = scaleX(x);
        double ys = scaleY(y);
        int ws = metrics.stringWidth(s);
        int hs = metrics.getDescent();
        offscreen.drawString(s, (float) (xs - ws/2.0), (float) (ys + hs));
        draw();
    }
    /**
     * Write the given text string in the current font, centered on (x, y) and
     * rotated by the specified number of degrees  
     * @param x the center x-coordinate of the text
     * @param y the center y-coordinate of the text
     * @param s the text
     * @param degrees is the number of degrees to rotate counterclockwise
     */
    public static void text(double x, double y, String s, double degrees) {
        double xs = scaleX(x);
        double ys = scaleY(y);
        offscreen.rotate(Math.toRadians(-degrees), xs, ys);
        text(x, y, s);
        offscreen.rotate(Math.toRadians(+degrees), xs, ys);
    }
    /**
     * Write the given text string in the current font, left-aligned at (x, y).
     * @param x the x-coordinate of the text
     * @param y the y-coordinate of the text
     * @param s the text
     */
    public static void textLeft(double x, double y, String s) {
        offscreen.setFont(font);
        FontMetrics metrics = offscreen.getFontMetrics();
        double xs = scaleX(x);
        double ys = scaleY(y);
        int hs = metrics.getDescent();
        offscreen.drawString(s, (float) (xs), (float) (ys + hs));
        draw();
    }
    /**
     * Write the given text string in the current font, right-aligned at (x, y).
     * @param x the x-coordinate of the text
     * @param y the y-coordinate of the text
     * @param s the text
     */
    public static void textRight(double x, double y, String s) {
        offscreen.setFont(font);
        FontMetrics metrics = offscreen.getFontMetrics();
        double xs = scaleX(x);
        double ys = scaleY(y);
        int ws = metrics.stringWidth(s);
        int hs = metrics.getDescent();
        offscreen.drawString(s, (float) (xs - ws), (float) (ys + hs));
        draw();
    }
    /**
     * Display on screen, pause for t milliseconds, and turn on
     * <em>animation mode</em>: subsequent calls to
     * drawing methods such as <tt>line()</tt>, <tt>circle()</tt>, and <tt>square()</tt>
     * will not be displayed on screen until the next call to <tt>show()</tt>.
     * This is useful for producing animations (clear the screen, draw a bunch of shapes,
     * display on screen for a fixed amount of time, and repeat). It also speeds up
     * drawing a huge number of shapes (call <tt>show(0)</tt> to defer drawing
     * on screen, draw the shapes, and call <tt>show(0)</tt> to display them all
     * on screen at once).
     * @param t number of milliseconds
     */
    public static void show(int t) {
        if (frame != null) defer = false;
        draw();
        try { Thread.sleep(t); }
        catch (InterruptedException e) { System.out.println("Error sleeping"); }
        defer = true;
    }
    /**
     * Display on-screen and turn off animation mode:
     * subsequent calls to
     * drawing methods such as <tt>line()</tt>, <tt>circle()</tt>, and <tt>square()</tt>
     * will be displayed on screen when called. This is the default.
     */
    public static void show() {
            if (frame != null) defer = false;
        draw();
    }
    // draw onscreen if defer is false
    private static void draw() {
        if (defer) return;
        onscreen.drawImage(offscreenImage, 0, 0, null);
        frame.repaint();
    }
   /*************************************************************************
    *  Save drawing to a file.
    *************************************************************************/
    /**
     * Save onscreen image to file - suffix must be png, jpg, or gif.
     * @param filename the name of the file with one of the required suffixes
     */
    public static void save(String filename) {
        File file = new File(filename);
        String suffix = filename.substring(filename.lastIndexOf('.') + 1);
        // png files
        if (suffix.toLowerCase().equals("png")) {
            try { ImageIO.write(onscreenImage, suffix, file); }
            catch (IOException e) { e.printStackTrace(); }
        }
        // need to change from ARGB to RGB for jpeg
        // reference: http://archives.java.sun.com/cgi-bin/wa?A2=ind0404&L=java2d-interest&D=0&P=2727
        else if (suffix.toLowerCase().equals("jpg")) {
            WritableRaster raster = onscreenImage.getRaster();
            WritableRaster newRaster;
            newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2});
            DirectColorModel cm = (DirectColorModel) onscreenImage.getColorModel();
            DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
                                                          cm.getRedMask(),
                                                          cm.getGreenMask(),
                                                          cm.getBlueMask());
            BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false,  null);
            try { ImageIO.write(rgbBuffer, suffix, file); }
            catch (IOException e) { e.printStackTrace(); }
        }
        else {
            System.out.println("Invalid image file type: " + suffix);
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void actionPerformed(ActionEvent e) {
        FileDialog chooser = new FileDialog(StdDraw.frame, "Use a .png or .jpg extension", FileDialog.SAVE);
        chooser.setVisible(true);
        String filename = chooser.getFile();
        if (filename != null) {
            StdDraw.save(chooser.getDirectory() + File.separator + chooser.getFile());
        }
    }
   /*************************************************************************
    *  Mouse interactions.
    *************************************************************************/
    /**
     * Is the mouse being pressed?
     * @return true or false
     */
    public static boolean
mousePressed() {
        synchronized (mouseLock) {
            return mousePressed;
        }
    }
    /**
     * What is the x-coordinate of the mouse?
     * @return the value of the x-coordinate of the mouse
     */
    public static double mouseX() {
        synchronized (mouseLock) {
            return mouseX;
        }
    }
    /**
     * What is the y-coordinate of the mouse?
     * @return the value of the y-coordinate of the mouse
     */
    public static double mouseY() {
        synchronized (mouseLock) {
            return mouseY;
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void mouseClicked(MouseEvent e) { }
    /**
     * This method cannot be called directly.
     */
    public void mouseEntered(MouseEvent e) { }
    /**
     * This method cannot be called directly.
     */
    public void mouseExited(MouseEvent e) { }
    /**
     * This method cannot be called directly.
     */
    public void mousePressed(MouseEvent e) {
        synchronized (mouseLock) {
            mouseX = StdDraw.userX(e.getX());
            mouseY = StdDraw.userY(e.getY());
            mousePressed = true;
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void mouseReleased(MouseEvent e) {
        synchronized (mouseLock) {
            mousePressed = false;
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void mouseDragged(MouseEvent e)  {
        synchronized (mouseLock) {
            mouseX = StdDraw.userX(e.getX());
            mouseY = StdDraw.userY(e.getY());
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void mouseMoved(MouseEvent e) {
        synchronized (mouseLock) {
            mouseX = StdDraw.userX(e.getX());
            mouseY = StdDraw.userY(e.getY());
        }
    }
   /*************************************************************************
    *  Keyboard interactions.
    *************************************************************************/
    /**
     * Has the user typed a key?
     * @return true if the user has typed a key, false otherwise
     */
    public static boolean hasNextKeyTyped() {
        synchronized (keyLock) {
            return !keysTyped.isEmpty();
        }
    }
    /**
     * What is the next key that was typed by the user? This method returns
     * a Unicode character corresponding to the key typed (such as 'a' or 'A').
     * It cannot identify action keys (such as F1
     * and arrow keys) or modifier keys (such as control).
     * @return the next Unicode key typed
     */
    public static char nextKeyTyped() {
        synchronized (keyLock) {
            return keysTyped.removeLast();
        }
    }
    /**
     * Is the keycode currently being pressed? This method takes as an argument
     * the keycode (corresponding to a physical key). It can handle action keys
     * (such as F1 and arrow keys) and modifier keys (such as shift and control).
     * See <a href = "http://download.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html">KeyEvent.java</a>
     * for a description of key codes.
     * @return true if keycode is currently being pressed, false otherwise
     */
    public static boolean isKeyPressed(int keycode) {
        synchronized (keyLock) {
            return keysDown.contains(keycode);
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void keyTyped(KeyEvent e) {
        synchronized (keyLock) {
            keysTyped.addFirst(e.getKeyChar());
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void keyPressed(KeyEvent e) {
        synchronized (keyLock) {
            keysDown.add(e.getKeyCode());
        }
    }
    /**
     * This method cannot be called directly.
     */
    public void keyReleased(KeyEvent e) {
        synchronized (keyLock) {
            keysDown.remove(e.getKeyCode());
        }
    }
    /**
     * Test client.
     */
    public static void main(String[] args) {
        StdDraw.square(.2, .8, .1);
        StdDraw.filledSquare(.8, .8, .2);
        StdDraw.circle(.8, .2, .2);
        StdDraw.setPenColor(StdDraw.BOOK_RED);
        StdDraw.setPenRadius(.02);
        StdDraw.arc(.8, .2, .1, 200, 45);
        // draw a blue diamond
        StdDraw.setPenRadius();
        StdDraw.setPenColor(StdDraw.BOOK_BLUE);
        double[] x = { .1, .2, .3, .2 };
        double[] y = { .2, .3, .2, .1 };
        StdDraw.filledPolygon(x, y);
        // text
        StdDraw.setPenColor(StdDraw.BLACK);
        StdDraw.text(0.2, 0.5, "black text");
        StdDraw.setPenColor(StdDraw.WHITE);
        StdDraw.text(0.8, 0.8, "white text");
    }
}
__MACOSX/._ALED-lab2 (1).zip
Lab2_2017.pdf
ALED	-	Laboratorio	2	 1	
 
LABORATORIO 2: RECURSIVIDAD	
Objetivos	
Entender	el	comportamiento	de	los	algoritmos	recursivos	
Implementación	y	modificación	de	algoritmos	recursivos	
Probar	el	consumo	de	recursos	de	los	algoritmos	recursivos 
Entender	diferencias	entre	algoritmos	con	una	solución	y	con	múltiples	soluciones	
Herramientas	proporcionadas	
En	el	moodle	de	la	asignatura	dispone	de	herramientas	para	la	corrección	automática	
de	 entregas	 de	 código.	 Estas	 herramientas	 son	 sensibles	 al	 uso	 de	
mayúsculas/minúsculas,	 por	 lo	 que	 deberá	 respetar	 escrupulosamente	 las	
instrucciones	 dadas	 en	 este	 guion	 respecto	 al	 nombre	de	 clases	 y	métodos.	 Si	 tiene	
dudas	 sobre	 cómo	 usar	 esta	 herramienta	 puede	 consultar	 alguno	 de	 los	 vídeo-
tutoriales	(screencast)	disponibles:		
http://www.lab.dit.upm.es/~prog/screencast/SubirProyectosEclipseAMoodle.flv		
Introducción	
El	software	de	juegos,	así	como	el	de	optimización	o	el	de	búsqueda	en	grafos	suele	
emplear	algoritmos	recursivos.	
En	 esta	 práctica	 vamos	 a	 trabajar	 con	 algoritmos	 que	 permiten	 crear	 y	 resolver	
juegos	 de	 laberintos.	 Un	 ejemplo	 de	 este	 tipo	 de	 juegos	 es	 el	 que	 se	 emplean	 en	
http://www.gamesolo.com/flash-game/maze.html	
Un	 juego	de	 laberinto	 tiene	dos	actividades	 fundamentales:	construir	el	 laberinto	a	
seguir	y	resolver	el	 laberinto.	Las	clases	con	las	que	trabajaremos	incluyen	métodos	
para	las	dos	actividades.	Además,	incluyen	métodos	para	dibujar	los	laberintos.	En	la	
siguiente	 figura	 tenemos	 un	 ejemplo	 de	 laberinto	 con	 el	 que	 vamos	 a	 trabajar.	
Algunos	detalles	específicos	de	los	laberintos	con	los	que	trabajaremos	son:	
1. La	 posición	 de	 salida	 que	 vamos	 a	 emplear	 es	 la	 1,1.	 Representada	
gráficamente	abajo	a	la	izquierda.	
2. El	laberinto	siempre	es	cuadrado	y	tiene	NxN	posiciones.	En	el	ejemplo	N=20.	
3. La	posición	que	buscamos	es	 la	posición	central	del	 laberinto.	 Si	N	es	 impar	
esa	posición	será	(N+1)/2,(N+1)/2,	y	si	es	par	N/2,N/2.	
ALED	-	Laboratorio	2	 2	
 
4. Los	 algoritmos	 de	 construcción	 de	 laberintos	 con	 los	 que	 trabajaremos	
permiten	llegar	a	cualquier	posición	del	laberinto	desde	cualquier	posición.	
5. En	 las	 implementaciones	 con	 las	 que	 trabajaremos,	 el	 camino	 de	 llegada	 al	
punto	 destino	 está	 representado	 en	 azul,	 y	 en	 gris	 están	 representados	
puntos	 por	 los	 que	hemos	pasado,	 y	 nos	 han	 llevado	 a	 puntos	muertos	 o	 a	
puntos	por	 los	que	ya	hemos	pasado	(debemos	evitar	meternos	en	ciclos	de	
donde	no	salimos).	En	rojo	están	marcados	el	punto	origen	y	destino.	
	
La	 práctica	 emplea	 la	 clase	 StdDraw.	 Es	 una	 clase	 que	 permite	 dibujar	 de	 forma	
sencilla	elementos	gráficos	como	líneas,	círculos,	puntos,	….	Pero	a	diferencia	de	las	
bibliotecas
estándar	 de	 Java,	 esta	 clase	 localiza	 las	 posiciones	 y	 tamaños	 de	 los	
objetos	mediante	parámetros	double	y	permite	escalar	 las	 figuras	de	forma	sencilla	
(frente	 a	 los	 valores	 enteros	 absolutos	 de	 las	 bibliotecas	 estándar).	 Este	 escalado	
permite	 ver	 en	 el	mismo	 espacio	 gráfico	 laberintos	 de	 diferente	 tamaño,	 sin	 tener	
que	 cambiar	 apenas	 nuestro	 programa.	 Otra	 diferencia	 importante	 es	 que	 la	
coordenada	 de	 origen	 del	 espacio	 gráfico	 está	 abajo	 a	 la	 izquierda	 (frente	 a	 la	
posición	de	arriba	a	 la	 izquierda,	que	es	 como	suelen	 trabajar	 las	bibliotecas	 Java).	
Esto	no	es	más	que	un	 simple	 resumen,	porque	 la	 representación	gráfica	no	es	un	
objetivo	fundamental	de	la	práctica.	
Actividades	a	desarrollar	
Descarga	del	proyecto	desde	Moodle	(Trabajo	previo)	
La	estructura	del	proyecto	a	desarrollar,	así	como	algunas	de	las	clases	necesarias	se	
encuentran	disponibles	en	moodle	junto	a	esta	guía	de	laboratorio:	
Antes	del	inicio	de	la	sesión	de	laboratorio,	deberá:	
1. Descargar	ALED-lab2.zip	
2. Crear	el	proyecto	java	ALED-lab2	en	Eclipse.	
ALED	-	Laboratorio	2	 3	
 
3. Importar	la	carpeta	fuente	src	de	ALED-lab2	en	ALED-lab2.zip.	
4. Explorar	las	clases	Laberinto	y	StdDraw.	
5. Contestar	a	las	preguntas	1-3.	
Implementar	el	método	resolver	(Trabajo	en	laboratorio)	
Vamos	 a	 implementar	 el	 método	 que	 permite	 encontrar	 el	 camino	 desde	 la	
posición	 origen	 a	 la	 posición	 destino.	 El	 método	 de	 la	 clase	 Laberinto	 que	
construye	 el	 laberinto,	 genera	un	 laberinto	 con	una	única	 solución.	 La	 búsqueda	
del	camino	se	implementa	en	dos	métodos	sobrecargados	resolver()	y	resolver(int	
x,int	 y,	 int	 pasos).	 El	 primero	 es	 público,	 es	 un	 método	 fachada;	 hace	
inicializaciones	antes	de	empezar	la	búsqueda,	y	llama	al	segundo	que	es	privado	y	
es	donde	realmente	se	busca	el	camino.	Nos	centraremos	en	este	segundo.	
La	clase	Laberinto	incluye	los	siguientes	atributos:	
 protected boolean[][] norte; 
 protected boolean[][] este; 
 protected boolean[][] sur; 
 protected boolean[][] oeste; 
 protected boolean[][] visitado; 
 
El	constructor	de	Laberinto	nos	ha	dejado	 inicializados	norte,	sur,	este	 y	oeste.	El	
método	resolver()	(el	punto	de	entrada	 fundamental	de	 la	clase)	deja	 inicializado	
visitado.	 Todos	 estos	 atributos	 son	 arrays	 de	 tamaño	N+2,N+2.	norte,	 sur,	 este,	 y	
oeste	nos	indican	cuando	una	posición	tiene	una	pared	en	sentido	norte,	sur,	este	u	
oeste.	Los	fija	el	generador	de	caminos	(la	implementación	de	la	construcción	del	
laberinto)	y,	en	general,	no	debemos	modificarlos.	Son	variables	algo	redundantes.	
Están	así	implementadas	para	hacer	más	sencillos	los	algoritmos	de	resolver,	pero	
debemos	saber	qué	norte[x][y]	==	sur[x][y+1]	(para	y	>=	0	e	y	<=	N)	y	este[x][y]	==	
oeste[x+1][y]	(para	x	>=	0	y		x	<=	N).	
	
	 	 Oeste																	x																					Este	
	
	 	 0	 1	 …	 N	 N+1	
Norte	
	
	
	
	
y	
	
Sur	
N+1	 	 	 	 	 	
N	 	 	 	 	 	
…	 	 	 	 	 	
1	 	 	 	 	 	
0	 	 	 	 	 	
	
ALED	-	Laboratorio	2	 4	
 
El	 atributo	 visitado	 nos	 servirá	 para	 controlar	 los	 caminos	 por	 los	 que	
anteriormente	hemos	pasado	y	no	nos	han	llevado	a	una	solución.	
El	 tamaño	 de	 todos	 estos	 arrays	 es	N+2,N+2	mientras	 que	 el	 laberinto	 como	 tal	
está	 representado	 en	 los	 rangos	 1..N,1..N.	 Todos	 los	 arrays	 tienen	 un	 marco	
exterior	 para	 identificar	 los	 límites	 del	 laberinto.	 Por	 ejemplo,	 visitados[0][y],	
visitados[N+1][y],	 visitados[x][0]	 y	 visitados[x][N+1]	 están	 inicializados	 a	 true,	 el	
resto	 a	 false.	 Deben	 estar	 siempre	 a	 true	 norte[x][0],	 sur[x][N+1],	 este[0][y]	 y	
oeste[N+1][y].	
Empezaremos	 implementando	el	método	resolver(int	 x,	 int	 y,	 int	pasos)	 de	 forma	
determinista	 (intentamos	 buscar	 caminos	 siempre	 en	 el	 mismo	 orden).	 Dos	
ejecuciones	con	el	mismo	laberinto,	encuentran	siempre	el	mismo	resultado	de	la	
misma	forma.	El	algoritmo	que	vamos	a	seguir	parte	de	una	posición	x,y	(x	>	0,	x	<	
N+1,	 y	 	 >	 0,	 y	 <	N+1),	 con	pasos	 igual	 a	p.	 Si	 esa	 posición	 ya	 ha	 sido	 visitada,	 la	
descartamos;	 si	 es	 la	 posición	 central	 (Math.round(N/2.0),	 Math.round(N/2.0))	
hemos	encontrado	el	punto	 central.	 Si	no	es	ninguno	de	esos	 casos	marcamos	 la	
posición	 como	 visitada,	 la	 pintamos	 de	 azul	 e	 intentamos	 resolver,	 de	 forma	
recursiva,	 moviéndonos	 en	 dirección	 norte,	 si	 no	 hay	 pared	 en	 esa	 dirección,	
después	en	dirección	este,	después	sur	y	después	oeste,	siempre	y	cuando	no	haya	
paredes,	 debemos	 explorar	 suponiendo	 que	 damos	 un	 paso	 (y	 por	 tanto	
incrementamos	en	uno	la	variable	pasos	de	la	llamada).	Hemos	elegido	como	orden	
las	 agujas	 del	 reloj.	 Si	 por	 ninguno	de	 esos	 caminos	hemos	 llegado	 a	 la	 posición	
central,	pintamos	la	posición	de	gris,	y	retornamos	diciendo	que	hemos	llegado	a	
punto	muerto	o	visitado.	El	método	devuelve	el	número	de	pasos	necesarios	para	
llegar	a	la	solución.	Si	esa	llamada	no	encuentra	solución	puede	devolver	0.	
El	pseudo	código	del	algoritmo	nos	queda:	
int resolver(int x, int y, int pasos) 
Si encontrado o visitado[x][y] return 0 o pasos; 
visitado[x][y] = true; 
 
// marcamos la posicion de azul 
StdDraw.setPenColor(StdDraw.BLUE); 
StdDraw.filledCircle(x + 0.5, y + 0.5, 0.25); 
StdDraw.show(0); 
 
Si hemos llegado el punto central 
 encontrado = true; 
 return pasos 
 
Si no hay pared en norte[x][y] resolver(x, y + 1, pasos+1); 
Si no hay pared en este[x][y] resolver(x + 1, y, pasos+1; 
Si no hay pared en sur[x][y] resolver(x, y – 1, pasos+1); 
Si no hay pared en oeste[x][y] resolver(x - 1, y, pasos+1); 
 
Si encontrado return pasos devueltos por resolver que ha llegado al centro; 
ALED	-	Laboratorio	2	 5	
 
 
// marcamos la posicion de gris 
StdDraw.setPenColor(StdDraw.GRAY); 
StdDraw.filledCircle(x + 0.5, y + 0.5, 0.25); 
StdDraw.show(0); 
return 0; 
Implementar	el	algoritmo	y	compilarlo.	
Para	 probar	 el	 algoritmo	 tenemos	 que	 configurar	 una	 ejecución	 que	 pase	 como	
argumento	 el	 valor	 N.	 Creamos	 una	 configuración	 de	 ejecución	 con	 Run->Run	
Configurations…;	 seleccionamos	 Java	 Applications	 (entre	 los	 tipos	 de	 ejecuciones	
de	 la	 ventana	 a	 la	 izquierda)	 y	 creamos	 una	 nueva	 configuración	 de	 ejecución,	
presionando	el	botón	de	nueva	configuración	(arriba	a	la	izquierda).	
	
En	la	carpeta	principal	de	la	configuración	de	ejecución	seleccionamos	el	proyecto,	
y	la	clase	Laberinto,	y	en	la	carpeta	de	argumento	ponemos	10	como	argumento	de	
programa.	
	
ALED	-	Laboratorio	2	 6	
 
1. Pruebe	la	ejecución	del	algoritmo	con	números	entre	5	y	100	(números	mayores	
pueden	crearnos	problemas	de	memoria	y	tiempos	de	ejecución).	
2. Responda	a	las	preguntas	4-6	al	final	de	este	documento.	
3. Documente	la	clase	y	genere	la	documentación	javadoc	correspondiente.	
ALED	-	Laboratorio	2	 7	
 
Algoritmo	con	exploración	aleatoria	y	tiempos	de	
ejecución	(Trabajo	en	laboratorio)	
Realizar	las	siguientes	pruebas:	
1. En	el	ejemplo	anterior	la	exploración	de	caminos	la	hacemos	dando	prioridad	
al	norte	 frente	al	resto,	al	este	 frente	al	sur	y	oeste,	y	al	sur	 frente	al	oeste.	
Podemos	 cambiar	 el	 algoritmo	 para	 explorar	 de	 forma	 aleatoria.	 Podemos	
utilizar	 Math.random()	 para	 elegir	 de	 forma	 aleatoria	 el	 camino	 que	
seguiremos	 (dentro	 de	 los	 posibles).	 Debemos	modificar	 el	 algoritmo	 para	
que	 tengan	 la	 misma	 probabilidad	 la	 exploración	 de	 cualquiera	 de	 los	
caminos.	
2. Modificaremos	 el	método	 público	 resolver()	 para	 sacar	 por	 salida	 estándar	
cuanto	 tiempo	 se	 ha	 tardado	 en	 resolver	 el	 camino.	 Podemos	 incluir	 como	
primera	sentencia	de	este	método	
long t=System.currentTimeMillis();	
y	como	última:	
System.out.println("Tiempo total "+(System.currentTimeMillis()-t));	
3. Podemos	ver	que	buena	parte	del	tiempo	se	va	en
la	representación	gráfica.	
Si	comentamos	las	sentencias		
StdDraw.show(0);	
del	 método	 resolver(int	 x,	 int	 y,	 int	 pasos)	 y	 la	 introducimos	 al	 final	 del	
método	resolver(),	solamente	se	hacen	las	actualizaciones	gráficas	cuando	la	
exploración	está	terminada.	Compara	los	tiempos	de	ejecución	de	esta	forma	
y	la	anterior	(cuando	se	actualiza	la	representación	gráfica	por	cada	paso).	
4. Responda	a	las	preguntas	7-10	al	final	de	este	documento.	
5. Podemos	generar	errores	en	el	programa	si	ejecutamos	con	una	N=1000.	
ALED	-	Laboratorio	2	 8	
 
Búsqueda	del	camino	comprobando	que	todas	las	
posiciones	son	accesibles	(Trabajo	después	de	
laboratorio)	
Las	implementaciones	que	hemos	hecho	tienen	sentido	si	el	laberinto	tiene	solución.	
Hay	 varios	 algoritmos	 para	 generar	 el	 laberinto;	 la	 solución	 que	 empleamos	 en	 la	
clase	 Laberinto	 genera	 laberintos	 con	 solución,	 y	 con	 todas	 las	 posiciones	 del	
laberinto	accesibles.	
Vamos	 a	 implementar	 la	 clase	 LaberintoTodoAccesible	 que	 extenderá	 la	 clase	
Laberinto,	y	añadirá	métodos	que	permitan	comprobar	que	todas	las	posiciones	del	
laberinto	 son	 accesibles	 antes	 de	 resolverlo.	 LaberintoTodoAccesible	 incluirá	 el	
método:	
public boolean compruebaAccesibilidad() 
Que	devuelve	 true	 cuando	 todas	 las	posiciones	del	 laberinto	 son	accesibles,	 y	 false	
cuando	alguna	posición	no	es	accesible	partiendo	desde	la	posición	1,1. 
Realizar	los	siguientes	pasos:	
1. Implementar	el	método	compruebaAccesibilidad.		
2. Documente	el	método	y	los	posibles	métodos	añadidos.	
3. La	clase	incluye	la	implementación	de:	
	
public boolean ejecutaConControlAccesibilidad(int numFilasColumnas) 
	
con	una	implementación	similar	al	método	main	de	Laberinto,	que	construye	un	
laberinto,	comprueba	que	todas	las	posiciones	son	accesibles,	y	si	es	así,	resuelve	
el	laberinto.	
4. Ejecutar	la	clase	LaberintoTodoAccesible		y	su	método	main	que	hace	llamadas	a	
ejecutaConControlAccesibilidad	 pasando	 como	 parámetro	 el	 número	 de	 filas	
del	laberinto.		
5. Hacer	pruebas	con	diferentes	tamaños	(5-100).	
Como	la	clase	Laberinto	siempre	genera	laberintos	con	todas	las	posiciones	accesibles,	
vamos	a	crear	un	método	en	la	clase	LaberintoTodoAccesible	 	que	nos	permita	aislar	
posiciones	 del	 laberinto,	 al	 que	 podemos	 llamar	 después	 de	 haber	 construido	 el	
laberinto,	 pero	 antes	 de	 comprobar	 la	 accesibilidad	 y	 de	 resolver	 el	 laberinto.	 La	
cabecera	puede	ser:	
 protected void aisla(int x, int y) 
Este	método	debe	 levantar	 las	4	paredes	de	 la	posición	que	 fijan	 los	parámetros	 x,y	
(teniendo	en	cuenta	que	esas	paredes	deben	ser	consistentes	con	las	de	sus	posiciones	
vecinas).	Tenemos	implementado	el	método:	
public boolean ejecutaConControlAccesibilidadYAislado(int numFilasColumnas) 
ALED	-	Laboratorio	2	 9	
 
Con	 la	misma	 implementación	 que	 ejecutaConControlAccesibilidad	 pero	 ejecutando	
aisla	para	una	cierta	posición	del	laberinto,	después	de	haber	construido	el	laberinto	y	
antes	 de	 comprobar	 la	 accesibilidad.	 El	 método	 main	 puede	 hacer	 llamadas	 	 a	
ejecutaConControlAccesibilidad o	 a ejecutaConControlAccesibilidadYAislado	 para	
hacer	ejecuciones	con	posiciones	aisladas	o	no	aisladas.	 	
6. Implementar	los	métodos	aisla.	
7. Documente	estos	los	métodos.	
8. Hacer	pruebas	con	diferentes	tamaños	(5-100).	
Entregas		
Instrucciones	para	la	entrega	durante	la	sesión	de	laboratorio:	
• Las	preguntas	planteadas	deben	entregarse	en	papel	al	final	de	la	sesión.	Las	
preguntas	1-3	estarán	resueltas	antes	del	 laboratorio,	y	el	resto	podrán	resolverse	
en	el	laboratorio.	
• El	código	fuente	y	la	documentación	de	la	clase	Laberinto.	Deberá	entregarse	
en	el	moodle	de	la	asignatura	antes	del	final	de	la	sesión	de	laboratorio.	
• El	 nombre	 del	 fichero	 que	 incluya	 los	 ficheros	 requeridos	 no	 debe	 contener	
tildes	ni	espacios.	
• En	el	 contenido	del	 fichero	 comprimido	de	 la	 entrega,	 el	 código	 fuente	debe	
estar	en	el	directorio	relativo:	“ALED-lab2/src/es/upm/dit/aled/lab2/”.	
Instrucciones	para	la	entrega	a	realizar	después	del	laboratorio:	
• El	código	fuente	y	la	documentación	de	las	clases	
LaberintoMultiplesSoluciones	y	Laberinto	deberán	entregarse	en	el	Moodle	
de	la	asignatura	antes	de	las	23:59	del	19	de	octubre,	siguiendo	las	mismas	
instrucciones	que	la	entrega	de	laboratorio	respecto	al	nombre	y	ruta	de	los	
ficheros.	
• Al	realizar	la	entrega	se	le	informará,	que	estará	sujeta	a	revisión	por	parte	del	
profesor,	así	como	información	sobre	algunos	fallos	detectados.	La	evaluación	
de	práctica	se	hará	con	el	siguiente	criterio:	
o 7	puntos	máximo	por	la	corrección	del	código	de	la	clase	Laberinto	y	
LaberintoTodoAccesible;	
o 3	puntos	máximo	por	la	corrección	de	la	documentación;	
• Para	la	evaluación	de	la	entrega	sólo	se	considerará	el	último	envío	realizado.	
• No	se	aceptarán	entregas	fuera	de	plazo	bajo	ningún	concepto.	
AVISO	MUY	IMPORTANTE	
ALED	-	Laboratorio	2	 10	
 
Se	 recuerda	 a	 los	 alumnos	 que	 el	 trabajo	 es	 individual,	 y	 que	 la	 copia	 de	 entregas	
supondrá	́el	suspenso	en	la	asignatura	de	forma	automática,	tanto	para	quien	copia	
como	para	quien	se	deja	copiar.	
No	está	permitido:	
• Realizar	este	trabajo	en	grupo.	
• Copiar	 el	 trabajo	 de	 otro	 alumno,	 ni	 permitir	 la	 copia	 del	 propio	 trabajo,	 ni	
siquiera	parcialmente.	
• Usar	código	publicado	sin	citar	el	origen.	
ALED	-	Laboratorio	2	 11	
 
Responda	 a	 las	 siguientes	 preguntas	 según	 se	 le	 indica	 en	 el	 enunciado	 del	
laboratorio.	Entregue	al	profesor	esta	hoja	con	sus	respuestas	antes	de	la	sesión.	
Nombre:_______________________________	 DNI/NIE:____________________	
1. Enumera	los	métodos	que	tiene	la	clase	Laberinto.	¿Cual	es	el	método	que	está	sin	
implementar?	
	
	
	
	
2. ¿Qué	argumentos	presupone	que	tendrá	el	método	main?	
	
	
	
3. ¿Desde	dónde	se	llama	al	método	generar?	¿Que	hace	ese	método?	
	
	
	
4. ¿Cuales	son	las	sentencias	de	Ejecución	Base	de	la	implementación	del	algoritmo?	
	
	
	
5. ¿Cuales	son	las	sentencias	de	Ejecución	Recursiva	de	la	implementación	del	
algoritmo?	
	
	
	
6. ¿Cuales	son	las	sentencias	de	Cálculos	Generales	de	la	implementación	del	
algoritmo?	
	
	
	
7. ¿Cómo	 modificas	 el	 algoritmo	 para	 seleccionar	 de	 forma	 aleatoria	 un	 camino,	
teniendo	en	cuenta	que	no	todos	los	caminos	se	pueden	explorar?	
ALED	-	Laboratorio	2	 12	
 
	
	
	
8. ¿Cuánto	 es	 el	 tiempo	 de	 ejecución	 para	 un	 laberinto	 de	 tamaño	 10?	 (cuando	 la	
actualización	gráfica	solo	se	hace	al	final	de	la	resolución)	
	
	
	
9. ¿Cuánto	 es	 el	 tiempo	 de	 ejecución	 para	 un	 laberinto	 de	 tamaño	 50?	 (cuando	 la	
actualización	 gráfica	 solo	 se	 hace	 al	 final	 de	 la	 resolución).	 Si	 los	 métodos	 de	
generación	de	 laberintos	 fallan	comenta	que	esto	ha	pasado	y	 reduce	el	 tamaño	
del	laberinto	para	que	esto	no	suceda.	
	
	
	
	
10. ¿Cuánto	es	el	 tiempo	de	ejecución	para	un	 laberinto	de	 tamaño	100?	 (cuando	 la	
actualización	 gráfica	 solo	 se	 hace	 al	 final	 de	 la	 resolución).	 Si	 los	 métodos	 de	
generación	de	 laberintos	fallan,	comenta	que	esto	ha	pasado	y	reduce	el	 tamaño	
del	laberinto	para	que	esto	no	suceda.	
	
	
	
	
__MACOSX/._Lab2_2017.pdf

Otros materiales