All Downloads are FREE. Search and download functionalities are using the official Maven repository.

stanford.karel.KarelProgram Maven / Gradle / Ivy

Go to download

This the original Stanford Karel for Java, packaged for Maven. ACM Library is included. See also https://cs.stanford.edu/people/eroberts/karel-the-robot-learns-java.pdf

The newest version!
/*
 * File: KarelProgram.java
 * -----------------------
 * This file implements the KarelProgram class.
 */

package stanford.karel;

import acm.program.*;
import acm.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.nio.file.Paths;
import java.util.*;

/**
 * This class is a subclass of Program
 * that runs a turtle program.
 */
public class KarelProgram extends Program {

    public static final int NORTH = KarelWorld.NORTH;
    public static final int EAST = KarelWorld.EAST;
    public static final int SOUTH = KarelWorld.SOUTH;
    public static final int WEST = KarelWorld.WEST;

    public static final int INFINITE = KarelWorld.INFINITE;

    public static final int SIMPLE = KarelWorld.SIMPLE;
    public static final int FANCY = KarelWorld.FANCY;

    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;

    /* Constructor: KarelProgram() */
    /**
     * Creates a new turtle program.
     *
     * KarelProgram program = new KarelProgram();
     */
    public KarelProgram() {
        world = createWorld();
        world.setRepaintFlag(false);
        world.setDisplayFlag(false);
        world.init(10, 10);
        Panel panel = new Panel();
        panel.setLayout(new BorderLayout());
        panel.add(BorderLayout.CENTER, world);
        controlPanel = new KarelControlPanel(this);
        world.setMonitor(controlPanel);
        panel.add(BorderLayout.WEST, controlPanel);
        add(panel);
        validate();
    }

    /* Method: main() */
    /**
     * Contains the code to be executed for each specific program subclass. If you
     * are defining your own KarelProgram class, you need to override
     * the definition of main so that it contains the code for your
     * application.
     */
    public void main() {
        /* Empty */
    }

    /* Method: getWorld() */
    /**
     * Returns the KarelWorld object in which Karel lives.
     *
     * KarelWorld world = getWorld();
     * @return The KarelWorld object in which Karel lives
     */
    public KarelWorld getWorld() {
        return world;
    }

    /* Static method: getWorldDirectory() */
    /**
     * Returns the default directory in which Karel's worlds live.
     *
     * String path = KarelProgram.getWorldDirectory();
     *
     * @return The directory in which Karel's worlds lives
     */
    public static String getWorldDirectory() {
        String dir = System.getProperty("user.dir");
        if (new File(dir, "worlds").isDirectory()) {
            dir += "/worlds";
        }
        return dir;
    }

    /* Factory method: createWorld() */
    /**
     * Creates the KarelWorld in which Karel lives. Subclasses can
     * override this method to create their own KarelWorld types.
     *
     * KarelWorld world = program.createWorld();
     *
     * @return The World object in which Karel lives
     */
    protected KarelWorld createWorld() {
        return new KarelWorld();
    }

    /* Protected method: isStarted() */
    /**
     * Checks to see whether this program has started.
     */
    protected boolean isStarted() {
        if (world == null || !super.isStarted())
            return false;
        Dimension size = world.getSize();
        if ((size == null) || (size.width == 0) || (size.height == 0))
            return false;
        return true;
    }

    protected Karel getKarel() {
        return world.getKarel();
    }

    public void add(Karel karel) {
        add(karel, 1, 1, KarelWorld.EAST, KarelWorld.INFINITE);
    }

    public void add(Karel karel, int x, int y, int dir, int nBeepers) {
        karel.setLocation(x, y);
        karel.setDirection(dir);
        karel.setBeepersInBag(nBeepers);
        world.add(karel);
    }

    public void start(String[] args) {
        super.start(args);
    }

    protected void setStartupObject(Object obj) {
        super.setStartupObject(obj);
    }

    /**
     * Returns the outermost class that implements stanford.karel.Karel
     *
     * @return the outermost class implementing stanford.karel.Karel or null
     */
    protected Class findKarelClass() {
        // The security manager can get the current stack trace.
        // However, the method is protected, so we subclass anonymously
        // and define a public method that does the same thing.
        Class[] currentContext = new SecurityManager() {
            public Class[] publicClassContext() {
                return this.getClassContext();
            }
        }.publicClassContext();
        for (int i = currentContext.length - 1; i >= 0; i--) {
            Class currentClass = currentContext[i];
            System.out.print("Examining: ");
            while (currentClass != null) {
                System.out.print("->" + currentClass.getName());
                if ("stanford.karel.Karel".equals(currentClass.getName())) {
                    break;
                }
                currentClass = currentClass.getSuperclass();
            }
            System.out.println();
            if (currentClass != null) {
                return currentContext[i];
            }
        }
        return null;
    }

    protected void startRun() {
        Karel karel = null;
        String karelClass = getParameter("karel");
        if (karelClass == null) {
            if (getStartupObject() instanceof Karel) {
                karel = (Karel) getStartupObject();
            }
            if (karel == null) {
                try {
                    karel = (Karel) findKarelClass().newInstance();
                } catch (Exception ex) {
                }
            }
            karelClass = karel.getClass().getName();
            karelClass = karelClass.substring(karelClass.lastIndexOf(".") + 1);
        } else {
            try {
                karel = (Karel) Class.forName(karelClass).newInstance();
            } catch (Exception ex) {
                System.out.println("Exception: " + ex);
            }
        }
        if (karel != null) {
            world.add(karel);
            setTitle(karelClass);
            String worldName = getParameter("world");
            if (worldName == null) {
                worldName = karelClass;
            }

            String inlineWorld = karel.getKarelWorld();
            if (null == inlineWorld) {
                try {
                    URL url;
                    if (Paths.get(System.getProperty("user.dir"), worldName + ".w").toFile().canRead()) {
                        url = new URL(getCodeBase(), worldName + ".w");
                    } else {
                        url = new URL(getCodeBase(), "Worlds/" + worldName + ".w");
                    }

                    URLConnection connection = url.openConnection();
                    world.load(new InputStreamReader(connection.getInputStream()));
                } catch (Exception ex) {
                    try {
                        System.out.println("World: " + worldName);
                        InputStream resourceStream = this.getClass().getResourceAsStream("/worlds/" + worldName + ".w");
                        world.load(new InputStreamReader(resourceStream));
                    } catch (Exception ex1) {
                        System.out.println("Exceptions: ");
                        ex.printStackTrace();
                        ex1.printStackTrace();
                    }
                }
            } else {
                world.load(inlineWorld.split("\n"));
            }
        }
        world.setRepaintFlag(true);
        world.setDisplayFlag(true);
        world.repaint();
        boolean firstTime = true;

        while (true) {
            if (firstTime) {
                started = karel.isAutorunEnabled();
                firstTime = false;
            } else {
                started = false;
            }

            synchronized (this) {
                while (!started) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                        /* Empty */
                    }
                }
            }
            try {
                if (karel == null) {
                    main();
                } else {
                    karel.run();
                }
            } catch (Exception ex) {
                if (errorDialog == null)
                    errorDialog = new KarelErrorDialog(this);
                errorDialog.error(ex.getMessage());
            }
        }
    }

    void signalStarted() {
        synchronized (this) {
            started = true;
            notifyAll();
        }
    }

    /* Private state */

    private KarelWorld world;
    private KarelControlPanel controlPanel;
    private KarelErrorDialog errorDialog;
    private boolean started;
}

/* Private class: KarelErrorDialog */
/**
 * The KarelErrorDialog class is used to display error messages in
 * Karel's world.
 */
class KarelErrorDialog extends Dialog implements WindowListener, ActionListener {

    public KarelErrorDialog(KarelProgram program) {
        super(JTFTools.getEnclosingFrame(program.getWorld()), true);
        setLayout(new BorderLayout());
        init();
    }

    private void init() {
        setSize(DIALOG_WIDTH, DIALOG_HEIGHT);
        setFont(DIALOG_FONT);
        setBackground(DIALOG_BGCOLOR);
        setResizable(false);
        addWindowListener(this);
        setLayout(new BorderLayout());
        HPanel hbox = new HPanel();
        VPanel vbox = new VPanel();
        bugIcon = new KarelBugIcon();
        okButton = new Button("OK");
        okButton.addActionListener(this);
        errorDisplay = new KarelErrorCanvas();
        errorDisplay.setFont(DIALOG_FONT);
        hbox.add("/width:" + LOGO_WIDTH + "/height:" + LOGO_HEIGHT, bugIcon);
        hbox.add("/stretch:both", errorDisplay);
        vbox.add("/stretch:both", hbox);
        vbox.add("/top:3/bottom:3/width:" + BUTTON_WIDTH + "/center", okButton);
        add(BorderLayout.CENTER, vbox);
        validate();
    }

    public void error(String msg) {
        errorDisplay.setText(msg);
        setVisible(true);
    }

    /* WindowListener interface */

    public void windowClosing(WindowEvent e) {
        setVisible(false);
    }

    public void windowOpened(WindowEvent e) {
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

    /* ActionListener interface */

    public void actionPerformed(ActionEvent e) {
        Component source = (Component) e.getSource();
        if (source == okButton)
            windowClosing(null);
    }

    /* Private constants */

    private static final int DIALOG_WIDTH = 330;
    private static final int DIALOG_HEIGHT = 170;
    private static final int LOGO_WIDTH = 100;
    private static final int LOGO_HEIGHT = 100;
    private static final int BUTTON_WIDTH = 60;
    private static final Font DIALOG_FONT = new Font("Dialog", Font.PLAIN, 12);
    private static final Color DIALOG_BGCOLOR = Color.RED;

    /* Private state */

    private Canvas bugIcon;
    private Button okButton;
    private KarelErrorCanvas errorDisplay;

}

class KarelErrorCanvas extends Canvas {

    public KarelErrorCanvas() {
        /* Empty */
    }

    public void setText(String msg) {
        errorText = msg;
        repaint();
    }

    public void paint(Graphics g) {
        FontMetrics fm = g.getFontMetrics();
        int x = LEFT_MARGIN;
        int y = TOP_MARGIN + fm.getAscent();
        int height = fm.getHeight();
        int limit = getSize().width - RIGHT_MARGIN;
        StringTokenizer tokenizer = new StringTokenizer(errorText, " ", true);
        while (tokenizer.hasMoreTokens()) {
            String word = tokenizer.nextToken();
            int width = fm.stringWidth(word);
            if (x + width > limit) {
                if (x > LEFT_MARGIN && !word.equals(" ")) {
                    x = LEFT_MARGIN;
                    y += height;
                }
            }
            g.drawString(word, x, y);
            x += width;
        }
    }

    /* Private constants */

    private static final int LEFT_MARGIN = 5;
    private static final int RIGHT_MARGIN = 5;
    private static final int TOP_MARGIN = 40;

    /* Private state */

    private String errorText;

}

class KarelBugIcon extends Canvas {
    public KarelBugIcon() {
        image = MediaTools.createImage(KAREL_BUG_IMAGE);
    }

    public void paint(Graphics g) {
        g.drawImage(image, 0, 0, this);
    }

    private String[] KAREL_BUG_IMAGE = {
            "47494638396146005400910000FFFFFFFFCBFF77777700000021F90401000001002C000000004600",
            "54004102FF8C8F19C3ED0FA374AADA3B80DE5BF82F70E2388220305CEA9195E62782C8DB76E198AE",
            "4ACD79839778093DB61B6993D32178C5A19308781D4549A5A106D3540DCEE8B07522552790690FDA",
            "0C6BBA6BE838B2334F6F1010230B3369AD15A6FC0F88C337B82241788868416698D817F808B8D5E8",
            "67E302A422544975888527C0259546D366244848E975E2F904846A3AE8C7CA4A9A97257668CB41F6",
            "71F7F5C386B4B4D810588A1663B4EA89220C1107F9578A5C14DCC8028D7D24696D35ECCCBD942DCE",
            "0C7E3D7EBE7D3A67FCC1A7A749CEB9FE4E6A31045F0D4BED951A9A0A6AA293B47C7C6285F8055096",
            "AD5FC75E153CE22480427A72D2A9A03451E18240FF163140CCA8A65FAE5BEACEF850304BE1948E8A",
            "526D4249EF1EC39004BD35FC085254A63D2CBCB93A63925D4652F116C049F0B3075012B6D07479F3",
            "2DDC39A254F1A181FAC0D154683759EA48BAD58CD772488F923DDBC72CDAB5577C36606BCDEDDBB3",
            "60C3F2A46BF7D1D86E7921ED2D6486A2383D7F5B7EECC54BEECC778591AE43766985BF5C8DAFCC53",
            "D3CEDE4E7E2FF531DDDC0FE6CE9145F91255594FE2A87D9D1FD26AA3DA9FC8D52E497AD67409E428",
            "D2BAE44D43981075BF8ABE21BF08CE86B743D3963281AC5B5A09C677BA3F6D8C543C68F5D91CB36B",
            "CF49EBE672E99FAB8798B5D2BB09D1F7D2E06BCD7CB8A427E17D88D4E69B7285D1E0E14B8F279D4E",
            "185D00D35B4F8B28579E3298D157934F80C4D41E836160B5C883C7C8321B757434334C3126258821",
            "3F14CE2555344B594295730771488163D888D7063CED8DC8C0336135E5143B0D4665CE39170EC459",
            "8C7719C5A3657D05C65A74F11DE9826D8840C7E49089407964658A288625237061A0D6966469E9E5",
            "975D86C90D96649EA2D899B0A4A966376CAA50000021FF0B4D414347436F6E200403103900000001",
            "5772697474656E20627920474946436F6E76657274657220322E342E33206F66204D6F6E6461792C",
            "204D61792032352C2031393938003B" };

    private Image image;

    public void exit() {
        System.out.println("Exit");
        // Don't do anything
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy