diff --git a/tests/test_course_1/_sources/activecode.rst b/tests/test_course_1/_sources/activecode.rst new file mode 100644 index 000000000..61db40840 --- /dev/null +++ b/tests/test_course_1/_sources/activecode.rst @@ -0,0 +1,2829 @@ +:orphan: + +This is copied directly from ``index.rst`` in the Runestone Components ActiveCode tests. + +ActiveCode Test +=============== +Note: an existing server-side test is named ``test_activecode_1``. So, we start numbering here at 2. + +.. activecode:: test_activecode_2 + + print("Hello World") + + +.. activecode:: test_activecode_2a + + This question has multiple lines of explanatory + text prior to the editing area or scaffolded code. + ~~~~ + print("Hello World") + + +.. activecode:: testprefixcode + + This is a question that has some hidden prefix code. + ~~~~ + for ch in "prefix": + print(ch) + hide = True + ^^^^ + # Your code Here + print("My Code") + ==== + if hide: + print("hidden code") + + +.. datafile:: Shape.java + :hide: + + public abstract class Shape { + String name; + public Shape(String name) { + this.name = name; + } + + public abstract double getArea(); + + public String getName() { + return this.name; + } + } + +.. activecode:: test_activecode_3 + :language: java + :datafile: Shape.java + + public class Square extends Shape { + double width; + public Square(String name, double width) { + super(name); + this.width = width; + } + + public double getArea() { + return width * width; + } + + public static void main(String args[]) { + Shape s = new Square("Box", 5); + System.out.print("Width: " + s.getArea()); + } + } + + +.. raw:: html + + + + + + +.. activecode:: test_activecode_4 + :language: java + :datafile: turtleClasses.jar, arch.jpg + + import java.awt.*; + import java.awt.font.*; + import java.awt.geom.*; + import java.awt.image.BufferedImage; + import java.text.*; + import java.util.*; + import java.util.List; // resolves problem with java.awt.List and java.util.List + + /** + * A class that represents a picture. This class inherits from + * SimplePicture and allows the student to add functionality to + * the Picture class. + * + * @author Barbara Ericson ericson@cc.gatech.edu + */ + public class Picture extends SimplePicture + { + ///////////////////// constructors ////////////////////////////////// + + /** + * Constructor that takes no arguments + */ + public Picture () + { + /* not needed but use it to show students the implicit call to super() + * child constructors always call a parent constructor + */ + super(); + } + + /** + * Constructor that takes a file name and creates the picture + * @param fileName the name of the file to create the picture from + */ + public Picture(String fileName) + { + // let the parent class handle this fileName + super(fileName); + } + + /** + * Constructor that takes the height and width + * @param height the height of the desired picture + * @param width the width of the desired picture + */ + public Picture(int height, int width) + { + // let the parent class handle this width and height + super(width,height); + } + + /** + * Constructor that takes a picture and creates a + * copy of that picture + * @param copyPicture the picture to copy + */ + public Picture(Picture copyPicture) + { + // let the parent class do the copy + super(copyPicture); + } + + /** + * Constructor that takes a buffered image + * @param image the buffered image to use + */ + public Picture(BufferedImage image) + { + super(image); + } + ////////////////////// methods /////////////////////////////////////// + + /** + * Method to return a string with information about this picture. + * @return a string with information about the picture such as fileName, + * height and width. + */ + public String toString() + { + String output = "Picture, filename " + getFileName() + + " height " + getHeight() + + " width " + getWidth(); + return output; + + } + + public void switchColors() + { + Pixel[][] pixels = this.getPixels2D(); + int red, green, blue = 0; + + for (Pixel[] rowArray : pixels) + { + for (Pixel p: rowArray) + { + red = p.getRed(); + green = p.getGreen(); + blue = p.getBlue(); + p.setRed(green); + p.setGreen(blue); + p.setBlue(red); + + } + } + } + + /* Main method for testing - each class in Java can have a main + * method + */ + public static void main(String[] args) + { + Picture arch = new Picture("arch.jpg"); + arch.show(); + arch.switchColors(); + arch.show(); + } + + } // this } is the end of class Picture, put all new methods before this + + +Support for SQL in the browser ? Yes! +-------------------------------------- +.. activecode:: test_activecode_6 + :language: sql + :autograde: unittest + :dburl: /_static/test.db + + select * from test; + + ===== + assert 1,1 == world + assert 0,1 == hello + assert 2,1 == 42 + +.. :dburl: http://dev.runestoneinteractive.org:8080/_static/bikeshare.db + + +.. activecode:: test_activecode_7 + :language: sql + :autograde: unittest + :dburl: /_static/test.db + + select * from test; + + +.. activecode:: sql3 + :language: sql + + CREATE TABLE contacts ( + contact_id INTEGER PRIMARY KEY, + first_name TEXT NOT NULL, + last_name TEXT NOT NULL, + email TEXT NOT NULL UNIQUE, + phone TEXT NOT NULL UNIQUE + ); + + + +.. datafile:: turtleClasses.jar + + import java.awt.Image; + import java.awt.image.BufferedImage; + + /** + * Interface to describe a digital picture. A digital picture can have an + * associated file name. It can have a title. It has pixels + * associated with it and you can get and set the pixels. You + * can get an Image from a picture or a BufferedImage. You can load + * it from a file name or image. You can show a picture. You can + * explore a picture. You can create a new image for it. + * + * @author Barb Ericson ericson@cc.gatech.edu + */ + public interface DigitalPicture + { + public String getFileName(); // get the file name that the picture came from + public String getTitle(); // get the title of the picture + public void setTitle(String title); // set the title of the picture + public int getWidth(); // get the width of the picture in pixels + public int getHeight(); // get the height of the picture in pixels + public Image getImage(); // get the image from the picture + public BufferedImage getBufferedImage(); // get the buffered image + public int getBasicPixel(int x, int y); // get the pixel information as an int + public void setBasicPixel(int x, int y, int rgb); // set the pixel information + public Pixel getPixel(int x, int y); // get the pixel information as an object + public Pixel[] getPixels(); // get all pixels in row-major order + public Pixel[][] getPixels2D(); // get 2-D array of pixels in row-major order + public void load(Image image); // load the image into the picture + public boolean load(String fileName); // load the picture from a file + public void show(); // show the picture + public boolean write(String fileName); // write out a file + } + import java.awt.Graphics; + + /** + * Interface to used to communicate between a model + * and its display + * + * Copyright Georgia Institute of Technology 2004 + * @author Barb Ericson ericson@cc.gatech.edu + */ + public interface ModelDisplay + { + /** method to notify the thing that displays that + * the model has changed */ + public void modelChanged(); + + /** method to add the model to the world + * @param model the model object to add */ + public void addModel(Object model); + + /** + * Method to remove the model from the world + * @param model the model object to remove */ + public void remove(Object model); + + /** + * Method that returns the graphics context + * for this model display + * @return the graphics context + */ + public Graphics getGraphics(); + + /** + * Method to clear the background + */ + public void clearBackground(); + + /** Method to get the width of the display + * @return the width in pixels of the display + */ + public int getWidth(); + + /** Method to get the height of the display + * @return the height in pixels of the display + */ + public int getHeight(); + } + import java.awt.*; + import java.awt.geom.*; + + /** + * This class represents a displayable path segment + * it has a color, width, and a Line2D object + * Copyright Georgia Institute of Technology 2005 + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class PathSegment + { + //////////////// fields ///////////////////// + private Color color; + private int width; + private Line2D.Float line; + + //////////////// constructors /////////////// + + /** + * Constructor that takes the color, width, + * and line + */ + public PathSegment (Color theColor, int theWidth, + Line2D.Float theLine) + { + this.color = theColor; + this.width = theWidth; + this.line = theLine; + } + + //////////////// methods //////////////////// + + /** + * Method to paint this path segment + * @param g the graphics context + */ + public void paintComponent(Graphics g) + { + Graphics2D g2 = (Graphics2D) g; + BasicStroke penStroke = new BasicStroke(this.width); + g2.setStroke(penStroke); + g2.setColor(this.color); + g2.draw(this.line); + } + + } // end of class + import java.awt.*; + import java.awt.geom.*; + import javax.swing.*; + import java.util.List; + import java.util.ArrayList; + import java.util.Iterator; + + /** + * Class to represent a pen which has a color, width, + * and a list of path segments that it should draw. + * A pen also knows if it is up or down + * + * Copyright Georgia Institute of Technology 2004 + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class Pen + { + ////////////////// fields ////////////////////// + + /** track if up or down */ + private boolean penDown = true; + + /** color of ink */ + private Color color = Color.green; + + /** width of stroke */ + private int width = 1; + + /** list of path segment objects to draw */ + private List pathSegmentList = + new ArrayList(); + + //////////////// constructors /////////////////// + + /** + * Constructor that takes no arguments + */ + public Pen() { } + + /** + * Constructor that takes all the ink color, and width + * @param color the ink color + * @param width the width in pixels + */ + public Pen(Color color, int width) + { + this.color = color; + this.width = width; + } + + /** + * Constructor that takes the ink color, width, and penDown flag + * @param color the ink color + * @param width the width in pixels + * @param penDown the flag if the pen is down + */ + public Pen(Color color, int width, boolean penDown) + { + // use the other constructor to set these + this(color,width); + + // set the pen down flag + this.penDown = penDown; + } + + ////////////////// methods /////////////////////// + + /** + * Method to get pen down status + * @return true if the pen is down else false + */ + public boolean isPenDown() { return penDown; } + + /** + * Method to set the pen down value + * @param value the new value to use + */ + public void setPenDown(boolean value) { penDown = value; } + + /** + * Method to get the pen (ink) color + * @return the ink color + */ + public Color getColor() { return color; } + + /** + * Method to set the pen (ink) color + * @param color the color to use + */ + public void setColor(Color color) { this.color = color;} + + /** + * Method to get the width of the pen + * @return the width in pixels + */ + public int getWidth() { return width; } + + /** + * Method to set the width of the pen + * @param width the width to use in pixels + */ + public void setWidth(int width) { this.width = width; } + + /** + * Method to add a path segment if the pen is down + * @param x1 the first x + * @param y1 the first y + * @param x2 the second x + * @param y2 the second y + */ + public synchronized void addMove(int x1, int y1, int x2, int y2) + { + if (penDown) + { + PathSegment pathSeg = + new PathSegment(this.color,this.width, + new Line2D.Float(x1,y1,x2,y2)); + pathSegmentList.add(pathSeg); + } + } + + /** + * Method to clear the path stored for this pen + */ + public void clearPath() + { + pathSegmentList.clear(); + } + + /** + * Metod to paint the pen path + * @param g the graphics context + */ + public synchronized void paintComponent(Graphics g) + { + + Color oldcolor = g.getColor(); + + // loop through path segment list and + Iterator iterator = pathSegmentList.iterator(); + PathSegment pathSeg = null; + + // loop through path segments + while (iterator.hasNext()) + { + pathSeg = (PathSegment) iterator.next(); + pathSeg.paintComponent(g); + } + + g.setColor(oldcolor); + } + + } // end of class + + + import java.awt.Color; + + /** + * Class that references a pixel in a picture. Pixel + * stands for picture element where picture is + * abbreviated pix. A pixel has a column (x) and + * row (y) location in a picture. A pixel knows how + * to get and set the red, green, blue, and alpha + * values in the picture. A pixel also knows how to get + * and set the color using a Color object. + * + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class Pixel + { + + ////////////////////////// fields /////////////////////////////////// + + /** the digital picture this pixel belongs to */ + private DigitalPicture picture; + + /** the x (column) location of this pixel in the picture; (0,0) is top left */ + private int x; + + /** the y (row) location of this pixel in the picture; (0,0) is top left */ + private int y; + + ////////////////////// constructors ///////////////////////////////// + + /** + * A constructor that takes the x and y location for the pixel and + * the picture the pixel is coming from + * @param picture the picture that the pixel is in + * @param x the x location of the pixel in the picture + * @param y the y location of the pixel in the picture + */ + public Pixel(DigitalPicture picture, int x, int y) + { + // set the picture + this.picture = picture; + + // set the x location + this.x = x; + + // set the y location + this.y = y; + + } + + ///////////////////////// methods ////////////////////////////// + + /** + * Method to get the x location of this pixel. + * @return the x location of the pixel in the picture + */ + public int getX() { return x; } + + /** + * Method to get the y location of this pixel. + * @return the y location of the pixel in the picture + */ + public int getY() { return y; } + + /** + * Method to get the row (y value) + * @return the row (y value) of the pixel in the picture + */ + public int getRow() { return y; } + + /** + * Method to get the column (x value) + * @return the column (x value) of the pixel + */ + public int getCol() { return x; } + + /** + * Method to get the amount of alpha (transparency) at this pixel. + * It will be from 0-255. + * @return the amount of alpha (transparency) + */ + public int getAlpha() { + + /* get the value at the location from the picture as a 32 bit int + * with alpha, red, green, blue each taking 8 bits from left to right + */ + int value = picture.getBasicPixel(x,y); + + // get the alpha value (starts at 25 so shift right 24) + // then and it with all 1's for the first 8 bits to keep + // end up with from 0 to 255 + int alpha = (value >> 24) & 0xff; + + return alpha; + } + + /** + * Method to get the amount of red at this pixel. It will be + * from 0-255 with 0 being no red and 255 being as much red as + * you can have. + * @return the amount of red from 0 for none to 255 for max + */ + public int getRed() { + + /* get the value at the location from the picture as a 32 bit int + * with alpha, red, green, blue each taking 8 bits from left to right + */ + int value = picture.getBasicPixel(x,y); + + // get the red value (starts at 17 so shift right 16) + // then AND it with all 1's for the first 8 bits to + // end up with a resulting value from 0 to 255 + int red = (value >> 16) & 0xff; + + return red; + } + + /** + * Method to get the red value from a pixel represented as an int + * @param value the color value as an int + * @return the amount of red + */ + public static int getRed(int value) + { + int red = (value >> 16) & 0xff; + return red; + } + + /** + * Method to get the amount of green at this pixel. It will be + * from 0-255 with 0 being no green and 255 being as much green as + * you can have. + * @return the amount of green from 0 for none to 255 for max + */ + public int getGreen() { + + /* get the value at the location from the picture as a 32 bit int + * with alpha, red, green, blue each taking 8 bits from left to right + */ + int value = picture.getBasicPixel(x,y); + + // get the green value (starts at 9 so shift right 8) + int green = (value >> 8) & 0xff; + + return green; + } + + /** + * Method to get the green value from a pixel represented as an int + * @param value the color value as an int + * @return the amount of green + */ + public static int getGreen(int value) + { + int green = (value >> 8) & 0xff; + return green; + } + + /** + * Method to get the amount of blue at this pixel. It will be + * from 0-255 with 0 being no blue and 255 being as much blue as + * you can have. + * @return the amount of blue from 0 for none to 255 for max + */ + public int getBlue() { + + /* get the value at the location from the picture as a 32 bit int + * with alpha, red, green, blue each taking 8 bits from left to right + */ + int value = picture.getBasicPixel(x,y); + + // get the blue value (starts at 0 so no shift required) + int blue = value & 0xff; + + return blue; + } + + /** + * Method to get the blue value from a pixel represented as an int + * @param value the color value as an int + * @return the amount of blue + */ + public static int getBlue(int value) + { + int blue = value & 0xff; + return blue; + } + + /** + * Method to get a color object that represents the color at this pixel. + * @return a color object that represents the pixel color + */ + public Color getColor() + { + /* get the value at the location from the picture as a 32 bit int + * with alpha, red, green, blue each taking 8 bits from left to right + */ + int value = picture.getBasicPixel(x,y); + + // get the red value (starts at 17 so shift right 16) + // then AND it with all 1's for the first 8 bits to + // end up with a resulting value from 0 to 255 + int red = (value >> 16) & 0xff; + + // get the green value (starts at 9 so shift right 8) + int green = (value >> 8) & 0xff; + + // get the blue value (starts at 0 so no shift required) + int blue = value & 0xff; + + return new Color(red,green,blue); + } + + /** + * Method to set the pixel color to the passed in color object. + * @param newColor the new color to use + */ + public void setColor(Color newColor) + { + // set the red, green, and blue values + int red = newColor.getRed(); + int green = newColor.getGreen(); + int blue = newColor.getBlue(); + + // update the associated picture + updatePicture(this.getAlpha(),red,green,blue); + } + + /** + * Method to update the picture based on the passed color + * values for this pixel + * @param alpha the alpha (transparency) at this pixel + * @param red the red value for the color at this pixel + * @param green the green value for the color at this pixel + * @param blue the blue value for the color at this pixel + */ + public void updatePicture(int alpha, int red, int green, int blue) + { + // create a 32 bit int with alpha, red, green blue from left to right + int value = (alpha << 24) + (red << 16) + (green << 8) + blue; + + // update the picture with the int value + picture.setBasicPixel(x,y,value); + } + + /** + * Method to correct a color value to be within 0 to 255 + * @param the value to use + * @return a value within 0 to 255 + */ + private static int correctValue(int value) + { + if (value < 0) + value = 0; + if (value > 255) + value = 255; + return value; + } + + /** + * Method to set the red to a new red value + * @param value the new value to use + */ + public void setRed(int value) + { + // set the red value to the corrected value + int red = correctValue(value); + + // update the pixel value in the picture + updatePicture(getAlpha(), red, getGreen(), getBlue()); + } + + /** + * Method to set the green to a new green value + * @param value the value to use + */ + public void setGreen(int value) + { + // set the green value to the corrected value + int green = correctValue(value); + + // update the pixel value in the picture + updatePicture(getAlpha(), getRed(), green, getBlue()); + } + + /** + * Method to set the blue to a new blue value + * @param value the new value to use + */ + public void setBlue(int value) + { + // set the blue value to the corrected value + int blue = correctValue(value); + + // update the pixel value in the picture + updatePicture(getAlpha(), getRed(), getGreen(), blue); + } + + /** + * Method to set the alpha (transparency) to a new alpha value + * @param value the new value to use + */ + public void setAlpha(int value) + { + // make sure that the alpha is from 0 to 255 + int alpha = correctValue(value); + + // update the associated picture + updatePicture(alpha, getRed(), getGreen(), getBlue()); + } + + /** + * Method to get the distance between this pixel's color and the passed color + * @param testColor the color to compare to + * @return the distance between this pixel's color and the passed color + */ + public double colorDistance(Color testColor) + { + double redDistance = this.getRed() - testColor.getRed(); + double greenDistance = this.getGreen() - testColor.getGreen(); + double blueDistance = this.getBlue() - testColor.getBlue(); + double distance = Math.sqrt(redDistance * redDistance + + greenDistance * greenDistance + + blueDistance * blueDistance); + return distance; + } + + /** + * Method to compute the color distances between two color objects + * @param color1 a color object + * @param color2 a color object + * @return the distance between the two colors + */ + public static double colorDistance(Color color1,Color color2) + { + double redDistance = color1.getRed() - color2.getRed(); + double greenDistance = color1.getGreen() - color2.getGreen(); + double blueDistance = color1.getBlue() - color2.getBlue(); + double distance = Math.sqrt(redDistance * redDistance + + greenDistance * greenDistance + + blueDistance * blueDistance); + return distance; + } + + /** + * Method to get the average of the colors of this pixel + * @return the average of the red, green, and blue values + */ + public double getAverage() + { + double average = (getRed() + getGreen() + getBlue()) / 3.0; + return average; + } + + /** + * Method to return a string with information about this pixel + * @return a string with information about this pixel + */ + public String toString() + { + return "Pixel row=" + getRow() + + " col=" + getCol() + + " red=" + getRed() + + " green=" + getGreen() + + " blue=" + getBlue(); + } + + } + import javax.imageio.ImageIO; + import java.awt.image.BufferedImage; + import javax.swing.ImageIcon; + import java.awt.*; + import java.io.*; + import java.awt.geom.*; + + import java.io.ByteArrayOutputStream; + // import javax.xml.bind.DatatypeConverter; + // Using java.util.Base64 instead of javax.xml.bind + import java.util.Base64; + import java.util.Scanner; + + /** + * A class that represents a simple picture. A simple picture may have + * an associated file name and a title. A simple picture has pixels, + * width, and height. A simple picture uses a BufferedImage to + * hold the pixels. You can also explore a simple picture. + * + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class SimplePicture implements DigitalPicture + { + + /////////////////////// Fields ///////////////////////// + + /** + * the file name associated with the simple picture + */ + private String fileName; + + /** + * the path name for the file + */ + private String pathName; + + /** + * the title of the simple picture + */ + private String title; + + /** + * buffered image to hold pixels for the simple picture + */ + private BufferedImage bufferedImage; + + /** + * extension for this file (jpg or bmp) + */ + private String extension; + + + /////////////////////// Constructors ///////////////////////// + + /** + * A Constructor that takes no arguments. It creates a picture with + * a width of 200 and a height of 100 that is all white. + * A no-argument constructor must be given in order for a class to + * be able to be subclassed. By default all subclasses will implicitly + * call this in their parent's no-argument constructor unless a + * different call to super() is explicitly made as the first line + * of code in a constructor. + */ + public SimplePicture() + {this(200,100);} + + /** + * A Constructor that takes a file name and uses the file to create + * a picture + * @param fileName the file name to use in creating the picture + */ + public SimplePicture(String fileName) + { + + // load the picture into the buffered image + load(fileName); + + } + + /** + * A constructor that takes the width and height desired for a picture and + * creates a buffered image of that size. This constructor doesn't + * show the picture. The pixels will all be white. + * @param width the desired width + * @param height the desired height + */ + public SimplePicture(int width, int height) + { + bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + title = "None"; + fileName = "None"; + extension = "jpg"; + setAllPixelsToAColor(Color.white); + } + + /** + * A constructor that takes the width and height desired for a picture and + * creates a buffered image of that size. It also takes the + * color to use for the background of the picture. + * @param width the desired width + * @param height the desired height + * @param theColor the background color for the picture + */ + public SimplePicture(int width, int height, Color theColor) + { + this(width,height); + setAllPixelsToAColor(theColor); + } + + /** + * A Constructor that takes a picture to copy information from + * @param copyPicture the picture to copy from + */ + public SimplePicture(SimplePicture copyPicture) + { + if (copyPicture.fileName != null) + { + this.fileName = new String(copyPicture.fileName); + this.extension = copyPicture.extension; + } + if (copyPicture.title != null) + this.title = new String(copyPicture.title); + if (copyPicture.bufferedImage != null) + { + this.bufferedImage = new BufferedImage(copyPicture.getWidth(), + copyPicture.getHeight(), BufferedImage.TYPE_INT_RGB); + this.copyPicture(copyPicture); + } + } + + /** + * A constructor that takes a buffered image + * @param image the buffered image + */ + public SimplePicture(BufferedImage image) + { + this.bufferedImage = image; + title = "None"; + fileName = "None"; + extension = "jpg"; + } + + ////////////////////////// Methods ////////////////////////////////// + + /** + * Method to get the extension for this picture + * @return the extension (jpg, bmp, giff, etc) + */ + public String getExtension() { return extension; } + + /** + * Method that will copy all of the passed source picture into + * the current picture object + * @param sourcePicture the picture object to copy + */ + public void copyPicture(SimplePicture sourcePicture) + { + Pixel sourcePixel = null; + Pixel targetPixel = null; + + // loop through the columns + for (int sourceX = 0, targetX = 0; + sourceX < sourcePicture.getWidth() && + targetX < this.getWidth(); + sourceX++, targetX++) + { + // loop through the rows + for (int sourceY = 0, targetY = 0; + sourceY < sourcePicture.getHeight() && + targetY < this.getHeight(); + sourceY++, targetY++) + { + sourcePixel = sourcePicture.getPixel(sourceX,sourceY); + targetPixel = this.getPixel(targetX,targetY); + targetPixel.setColor(sourcePixel.getColor()); + } + } + + } + + /** + * Method to set the color in the picture to the passed color + * @param color the color to set to + */ + public void setAllPixelsToAColor(Color color) + { + // loop through all x + for (int x = 0; x < this.getWidth(); x++) + { + // loop through all y + for (int y = 0; y < this.getHeight(); y++) + { + getPixel(x,y).setColor(color); + } + } + } + + /** + * Method to get the buffered image + * @return the buffered image + */ + public BufferedImage getBufferedImage() + { + return bufferedImage; + } + + /** + * Method to get a graphics object for this picture to use to draw on + * @return a graphics object to use for drawing + */ + public Graphics getGraphics() + { + return bufferedImage.getGraphics(); + } + + /** + * Method to get a Graphics2D object for this picture which can + * be used to do 2D drawing on the picture + */ + public Graphics2D createGraphics() + { + return bufferedImage.createGraphics(); + } + + /** + * Method to get the file name associated with the picture + * @return the file name associated with the picture + */ + public String getFileName() { return fileName; } + + /** + * Method to set the file name + * @param name the full pathname of the file + */ + public void setFileName(String name) + { + fileName = name; + } + + /** + * Method to get the title of the picture + * @return the title of the picture + */ + public String getTitle() + { return title; } + + /** + * Method to set the title for the picture + * @param title the title to use for the picture + */ + public void setTitle(String title) + { + this.title = title; + } + + /** + * Method to get the width of the picture in pixels + * @return the width of the picture in pixels + */ + public int getWidth() { return bufferedImage.getWidth(); } + + /** + * Method to get the height of the picture in pixels + * @return the height of the picture in pixels + */ + public int getHeight() { return bufferedImage.getHeight(); } + + /** + * Method to get an image from the picture + * @return the buffered image since it is an image + */ + public Image getImage() + { + return bufferedImage; + } + + /** + * Method to return the pixel value as an int for the given x and y location + * @param x the x coordinate of the pixel + * @param y the y coordinate of the pixel + * @return the pixel value as an integer (alpha, red, green, blue) + */ + public int getBasicPixel(int x, int y) + { + return bufferedImage.getRGB(x,y); + } + + /** + * Method to set the value of a pixel in the picture from an int + * @param x the x coordinate of the pixel + * @param y the y coordinate of the pixel + * @param rgb the new rgb value of the pixel (alpha, red, green, blue) + */ + public void setBasicPixel(int x, int y, int rgb) + { + bufferedImage.setRGB(x,y,rgb); + } + + /** + * Method to get a pixel object for the given x and y location + * @param x the x location of the pixel in the picture + * @param y the y location of the pixel in the picture + * @return a Pixel object for this location + */ + public Pixel getPixel(int x, int y) + { + // create the pixel object for this picture and the given x and y location + Pixel pixel = new Pixel(this,x,y); + return pixel; + } + + /** + * Method to get a one-dimensional array of Pixels for this simple picture + * @return a one-dimensional array of Pixel objects starting with y=0 + * to y=height-1 and x=0 to x=width-1. + */ + public Pixel[] getPixels() + { + int width = getWidth(); + int height = getHeight(); + Pixel[] pixelArray = new Pixel[width * height]; + + // loop through height rows from top to bottom + for (int row = 0; row < height; row++) + for (int col = 0; col < width; col++) + pixelArray[row * width + col] = new Pixel(this,col,row); + + return pixelArray; + } + + /** + * Method to get a two-dimensional array of Pixels for this simple picture + * @return a two-dimensional array of Pixel objects in row-major order. + */ + public Pixel[][] getPixels2D() + { + int width = getWidth(); + int height = getHeight(); + Pixel[][] pixelArray = new Pixel[height][width]; + + // loop through height rows from top to bottom + for (int row = 0; row < height; row++) + for (int col = 0; col < width; col++) + pixelArray[row][col] = new Pixel(this,col,row); + + return pixelArray; + } + + /** + * Method to load the buffered image with the passed image + * @param image the image to use + */ + public void load(Image image) + { + // get a graphics context to use to draw on the buffered image + Graphics2D graphics2d = bufferedImage.createGraphics(); + + // draw the image on the buffered image starting at 0,0 + graphics2d.drawImage(image,0,0,null); + + // show the new image + show(); + } + + /** + * Method to show the picture in a picture frame + */ + public void show() + { + try { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + ImageIO.write(this.bufferedImage, "png", output); + String result = + // DatatypeConverter.printBase64Binary(output.toByteArray()); + // using java.util.Base64 instead of java.xml.bind.DataTypeConverter + Base64.getEncoder().encodeToString(output.toByteArray()); + System.out.println("<img src=\'data:image/" + this.extension + ";base64," + result + "\'/>"); + } catch (IOException e) { + System.out.println("Errors occured in image conversion"); + } + } + + /** + * Method to load the picture from the passed file name + * @param fileName the file name to use to load the picture from + * @throws IOException if the picture isn't found + */ + public void loadOrFail(String fileName) throws IOException + { + // set the current picture's file name + this.fileName = fileName; + + // set the extension + int posDot = fileName.lastIndexOf('.'); + if (posDot >= 0) + this.extension = fileName.substring(posDot + 1); + + //get file location + String[] paths = fileName.split("/"); + this.pathName = ""; + if(paths.length != 1) { + for(int i = 0; i < paths.length - 1; i++) { + this.pathName = this.pathName + paths[i] + "/"; + } + } + // if the current title is null use the file name + if (title == null) + title = fileName; + + File file = new File(this.fileName); + + if (!file.canRead()) + { + throw new IOException(this.fileName + + " could not be opened. Check that you specified the path"); + } + bufferedImage = ImageIO.read(file); + + + } + + + /** + * Method to read the contents of the picture from a filename + * without throwing errors + * @param fileName the name of the file to write the picture to + * @return true if success else false + */ + public boolean load(String fileName) + { + try { + this.loadOrFail(fileName); + return true; + + } catch (Exception ex) { + System.out.println("There was an error trying to open " + fileName); + bufferedImage = new BufferedImage(600,200, + BufferedImage.TYPE_INT_RGB); + addMessage("Couldn't load " + fileName,5,100); + return false; + } + + } + + /** + * Method to load the picture from the passed file name + * this just calls load(fileName) and is for name compatibility + * @param fileName the file name to use to load the picture from + * @return true if success else false + */ + public boolean loadImage(String fileName) + { + return load(fileName); + } + + /** + * Method to draw a message as a string on the buffered image + * @param message the message to draw on the buffered image + * @param xPos the x coordinate of the leftmost point of the string + * @param yPos the y coordinate of the bottom of the string + */ + public void addMessage(String message, int xPos, int yPos) + { + // get a graphics context to use to draw on the buffered image + Graphics2D graphics2d = bufferedImage.createGraphics(); + + // set the color to white + graphics2d.setPaint(Color.white); + + // set the font to Helvetica bold style and size 16 + graphics2d.setFont(new Font("Helvetica",Font.BOLD,16)); + + // draw the message + graphics2d.drawString(message,xPos,yPos); + + } + + /** + * Method to draw a string at the given location on the picture + * @param text the text to draw + * @param xPos the left x for the text + * @param yPos the top y for the text + */ + public void drawString(String text, int xPos, int yPos) + { + addMessage(text,xPos,yPos); + } + + /** + * Method to create a new picture by scaling the current + * picture by the given x and y factors + * @param xFactor the amount to scale in x + * @param yFactor the amount to scale in y + * @return the resulting picture + */ + public Picture scale(double xFactor, double yFactor) + { + // set up the scale transform + AffineTransform scaleTransform = new AffineTransform(); + scaleTransform.scale(xFactor,yFactor); + + // create a new picture object that is the right size + Picture result = new Picture((int) (getHeight() * yFactor), + (int) (getWidth() * xFactor)); + + // get the graphics 2d object to draw on the result + Graphics graphics = result.getGraphics(); + Graphics2D g2 = (Graphics2D) graphics; + + // draw the current image onto the result image scaled + g2.drawImage(this.getImage(),scaleTransform,null); + + return result; + } + + /** + * Method to create a new picture of the passed width. + * The aspect ratio of the width and height will stay + * the same. + * @param width the desired width + * @return the resulting picture + */ + public Picture getPictureWithWidth(int width) + { + // set up the scale transform + double xFactor = (double) width / this.getWidth(); + Picture result = scale(xFactor,xFactor); + return result; + } + + /** + * Method to create a new picture of the passed height. + * The aspect ratio of the width and height will stay + * the same. + * @param height the desired height + * @return the resulting picture + */ + public Picture getPictureWithHeight(int height) + { + // set up the scale transform + double yFactor = (double) height / this.getHeight(); + Picture result = scale(yFactor,yFactor); + return result; + } + + /** + * Method to load a picture from a file name and show it in a picture frame + * @param fileName the file name to load the picture from + * @return true if success else false + */ + public boolean loadPictureAndShowIt(String fileName) + { + boolean result = true; // the default is that it worked + + // try to load the picture into the buffered image from the file name + result = load(fileName); + + // show the picture in a picture frame + show(); + + return result; + } + + /** + * Method to write the contents of the picture to a file with + * the passed name + * @param fileName the name of the file to write the picture to + */ + public void writeOrFail(String fileName) throws IOException + { + String extension = this.extension; // the default is current + + // create the file object + File file = new File(fileName); + + // get the extension + int posDot = fileName.indexOf('.'); + if (posDot >= 0) + extension = fileName.substring(posDot + 1); + + // write the contents of the buffered image to the file + ImageIO.write(bufferedImage, extension, file); + + } + + /** + * Method to write the contents of the picture to a file with + * the passed name without throwing errors + * @param fileName the name of the file to write the picture to + * @return true if success else false + */ + public boolean write(String fileName) + { + try { + this.writeOrFail(fileName); + return true; + } catch (Exception ex) { + System.out.println("There was an error trying to write " + fileName); + ex.printStackTrace(); + return false; + } + + } + + /** + * Method to get the coordinates of the enclosing rectangle after this + * transformation is applied to the current picture + * @return the enclosing rectangle + */ + public Rectangle2D getTransformEnclosingRect(AffineTransform trans) + { + int width = getWidth(); + int height = getHeight(); + double maxX = width - 1; + double maxY = height - 1; + double minX, minY; + Point2D.Double p1 = new Point2D.Double(0,0); + Point2D.Double p2 = new Point2D.Double(maxX,0); + Point2D.Double p3 = new Point2D.Double(maxX,maxY); + Point2D.Double p4 = new Point2D.Double(0,maxY); + Point2D.Double result = new Point2D.Double(0,0); + Rectangle2D.Double rect = null; + + // get the new points and min x and y and max x and y + trans.deltaTransform(p1,result); + minX = result.getX(); + maxX = result.getX(); + minY = result.getY(); + maxY = result.getY(); + trans.deltaTransform(p2,result); + minX = Math.min(minX,result.getX()); + maxX = Math.max(maxX,result.getX()); + minY = Math.min(minY,result.getY()); + maxY = Math.max(maxY,result.getY()); + trans.deltaTransform(p3,result); + minX = Math.min(minX,result.getX()); + maxX = Math.max(maxX,result.getX()); + minY = Math.min(minY,result.getY()); + maxY = Math.max(maxY,result.getY()); + trans.deltaTransform(p4,result); + minX = Math.min(minX,result.getX()); + maxX = Math.max(maxX,result.getX()); + minY = Math.min(minY,result.getY()); + maxY = Math.max(maxY,result.getY()); + + // create the bounding rectangle to return + rect = new Rectangle2D.Double(minX,minY,maxX - minX + 1, maxY - minY + 1); + return rect; + } + + /** + * Method to get the coordinates of the enclosing rectangle after this + * transformation is applied to the current picture + * @return the enclosing rectangle + */ + public Rectangle2D getTranslationEnclosingRect(AffineTransform trans) + { + return getTransformEnclosingRect(trans); + } + + /** + * Method to return a string with information about this picture + * @return a string with information about the picture + */ + public String toString() + { + String output = "Simple Picture, filename " + fileName + + " height " + getHeight() + " width " + getWidth(); + return output; + } + + } // end of SimplePicture class + import javax.swing.*; + import java.awt.*; + import java.awt.font.*; + import java.awt.geom.*; + import java.util.Observer; + import java.util.Random; + + /** + * Class that represents a Logo-style turtle. The turtle + * starts off facing north. + * A turtle can have a name, has a starting x and y position, + * has a heading, has a width, has a height, has a visible + * flag, has a body color, can have a shell color, and has a pen. + * The turtle will not go beyond the model display or picture + * boundaries. + * + * You can display this turtle in either a picture or in + * a class that implements ModelDisplay. + * + * Copyright Georgia Institute of Technology 2004 + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class SimpleTurtle + { + ///////////////// fields //////////////////////// + + /** count of the number of turtles created */ + private static int numTurtles = 0; + + /** array of colors to use for the turtles */ + private static Color[] colorArray = { Color.green, Color.cyan, new Color(204,0,204), Color.gray}; + + /** who to notify about changes to this turtle */ + private ModelDisplay modelDisplay = null; + + /** picture to draw this turtle on */ + private Picture picture = null; + + /** width of turtle in pixels */ + private int width = 15; + + /** height of turtle in pixels */ + private int height = 18; + + /** current location in x (center) */ + private int xPos = 0; + + /** current location in y (center) */ + private int yPos = 0; + + /** heading angle */ + private double heading = 0; // default is facing north + + /** pen to use for this turtle */ + private Pen pen = new Pen(); + + /** color to draw the body in */ + private Color bodyColor = null; + + /** color to draw the shell in */ + private Color shellColor = null; + + /** color of information string */ + private Color infoColor = Color.black; + + /** flag to say if this turtle is visible */ + private boolean visible = true; + + /** flag to say if should show turtle info */ + private boolean showInfo = false; + + /** the name of this turtle */ + private String name = "No name"; + + ////////////////// constructors /////////////////// + + /** + * Constructor that takes the x and y position for the + * turtle + * @param x the x pos + * @param y the y pos + */ + public SimpleTurtle(int x, int y) + { + xPos = x; + yPos = y; + bodyColor = colorArray[numTurtles % colorArray.length]; + setPenColor(bodyColor); + numTurtles++; + } + + /** + * Constructor that takes the x and y position and the + * model displayer + * @param x the x pos + * @param y the y pos + * @param display the model display + */ + public SimpleTurtle(int x, int y, ModelDisplay display) + { + this(x,y); // invoke constructor that takes x and y + modelDisplay = display; + display.addModel(this); + } + + /** + * Constructor that takes a model display and adds + * a turtle in the middle of it + * @param display the model display + */ + public SimpleTurtle(ModelDisplay display) + { + // invoke constructor that takes x and y + this((int) (display.getWidth() / 2), + (int) (display.getHeight() / 2)); + modelDisplay = display; + display.addModel(this); + + } + + /** + * Constructor that takes the x and y position and the + * picture to draw on + * @param x the x pos + * @param y the y pos + * @param picture the picture to draw on + */ + public SimpleTurtle(int x, int y, Picture picture) + { + this(x,y); // invoke constructor that takes x and y + this.picture = picture; + this.visible = false; // default is not to see the turtle + } + + /** + * Constructor that takes the + * picture to draw on and will appear in the middle + * @param picture the picture to draw on + */ + public SimpleTurtle(Picture picture) + { + // invoke constructor that takes x and y + this((int) (picture.getWidth() / 2), + (int) (picture.getHeight() / 2)); + this.picture = picture; + this.visible = false; // default is not to see the turtle + } + + //////////////////// methods ///////////////////////// + + /** + * Get the distance from the passed x and y location + * @param x the x location + * @param y the y location + */ + public double getDistance(int x, int y) + { + int xDiff = x - xPos; + int yDiff = y - yPos; + return (Math.sqrt((xDiff * xDiff) + (yDiff * yDiff))); + } + + /** + * Method to turn to face another simple turtle + */ + public void turnToFace(SimpleTurtle turtle) + { + turnToFace(turtle.xPos,turtle.yPos); + } + + /** + * Method to turn towards the given x and y + * @param x the x to turn towards + * @param y the y to turn towards + */ + public void turnToFace(int x, int y) + { + double dx = x - this.xPos; + double dy = y - this.yPos; + double arcTan = 0.0; + double angle = 0.0; + + // avoid a divide by 0 + if (dx == 0) + { + // if below the current turtle + if (dy > 0) + heading = 180; + + // if above the current turtle + else if (dy < 0) + heading = 0; + } + // dx isn't 0 so can divide by it + else + { + arcTan = Math.toDegrees(Math.atan(dy / dx)); + if (dx < 0) + heading = arcTan - 90; + else + heading = arcTan + 90; + } + + // notify the display that we need to repaint + updateDisplay(); + } + + /** + * Method to get the picture for this simple turtle + * @return the picture for this turtle (may be null) + */ + public Picture getPicture() { return this.picture; } + + /** + * Method to set the picture for this simple turtle + * @param pict the picture to use + */ + public void setPicture(Picture pict) { this.picture = pict; } + + /** + * Method to get the model display for this simple turtle + * @return the model display if there is one else null + */ + public ModelDisplay getModelDisplay() { return this.modelDisplay; } + + /** + * Method to set the model display for this simple turtle + * @param theModelDisplay the model display to use + */ + public void setModelDisplay(ModelDisplay theModelDisplay) + { this.modelDisplay = theModelDisplay; } + + /** + * Method to get value of show info + * @return true if should show info, else false + */ + public boolean getShowInfo() { return this.showInfo; } + + /** + * Method to show the turtle information string + * @param value the value to set showInfo to + */ + public void setShowInfo(boolean value) { this.showInfo = value; } + + /** + * Method to get the shell color + * @return the shell color + */ + public Color getShellColor() + { + Color color = null; + if (this.shellColor == null && this.bodyColor != null) + color = bodyColor.darker(); + else color = this.shellColor; + return color; + } + + /** + * Method to set the shell color + * @param color the color to use + */ + public void setShellColor(Color color) { this.shellColor = color; } + + /** + * Method to get the body color + * @return the body color + */ + public Color getBodyColor() { return this.bodyColor; } + + /** + * Method to set the body color which + * will also set the pen color + * @param color the color to use + */ + public void setBodyColor(Color color) + { + this.bodyColor = color; + setPenColor(this.bodyColor); + } + + /** + * Method to set the color of the turtle. + * This will set the body color + * @param color the color to use + */ + public void setColor(Color color) { this.setBodyColor(color); } + + /** + * Method to get the information color + * @return the color of the information string + */ + public Color getInfoColor() { return this.infoColor; } + + /** + * Method to set the information color + * @param color the new color to use + */ + public void setInfoColor(Color color) { this.infoColor = color; } + + /** + * Method to return the width of this object + * @return the width in pixels + */ + public int getWidth() { return this.width; } + + /** + * Method to return the height of this object + * @return the height in pixels + */ + public int getHeight() { return this.height; } + + /** + * Method to set the width of this object + * @param theWidth in width in pixels + */ + public void setWidth(int theWidth) { this.width = theWidth; } + + /** + * Method to set the height of this object + * @param theHeight the height in pixels + */ + public void setHeight(int theHeight) { this.height = theHeight; } + + /** + * Method to get the current x position + * @return the x position (in pixels) + */ + public int getXPos() { return this.xPos; } + + /** + * Method to get the current y position + * @return the y position (in pixels) + */ + public int getYPos() { return this.yPos; } + + /** + * Method to get the pen + * @return the pen + */ + public Pen getPen() { return this.pen; } + + /** + * Method to set the pen + * @param thePen the new pen to use + */ + public void setPen(Pen thePen) { this.pen = thePen; } + + /** + * Method to check if the pen is down + * @return true if down else false + */ + public boolean isPenDown() { return this.pen.isPenDown(); } + + /** + * Method to set the pen down boolean variable + * @param value the value to set it to + */ + public void setPenDown(boolean value) { this.pen.setPenDown(value); } + + /** + * Method to lift the pen up + */ + public void penUp() { this.pen.setPenDown(false);} + + /** + * Method to set the pen down + */ + public void penDown() { this.pen.setPenDown(true);} + + /** + * Method to get the pen color + * @return the pen color + */ + public Color getPenColor() { return this.pen.getColor(); } + + /** + * Method to set the pen color + * @param color the color for the pen ink + */ + public void setPenColor(Color color) { this.pen.setColor(color); } + + /** + * Method to set the pen width + * @param width the width to use in pixels + */ + public void setPenWidth(int width) { this.pen.setWidth(width); } + + /** + * Method to get the pen width + * @return the width of the pen in pixels + */ + public int getPenWidth() { return this.pen.getWidth(); } + + /** + * Method to clear the path (history of + * where the turtle has been) + */ + public void clearPath() + { + this.pen.clearPath(); + } + + /** + * Method to get the current heading + * @return the heading in degrees + */ + public double getHeading() { return this.heading; } + + /** + * Method to set the heading + * @param heading the new heading to use + */ + public void setHeading(double heading) + { + this.heading = heading; + } + + /** + * Method to get the name of the turtle + * @return the name of this turtle + */ + public String getName() { return this.name; } + + /** + * Method to set the name of the turtle + * @param theName the new name to use + */ + public void setName(String theName) + { + this.name = theName; + } + + /** + * Method to get the value of the visible flag + * @return true if visible else false + */ + public boolean isVisible() { return this.visible;} + + /** + * Method to hide the turtle (stop showing it) + * This doesn't affect the pen status + */ + public void hide() { this.setVisible(false); } + + /** + * Method to show the turtle (doesn't affect + * the pen status + */ + public void show() { this.setVisible(true); } + + /** + * Method to set the visible flag + * @param value the value to set it to + */ + public void setVisible(boolean value) + { + // if the turtle wasn't visible and now is + if (visible == false && value == true) + { + // update the display + this.updateDisplay(); + } + + // set the visibile flag to the passed value + this.visible = value; + } + + /** + * Method to update the display of this turtle and + * also check that the turtle is in the bounds + */ + public synchronized void updateDisplay() + { + // check that x and y are at least 0 + if (xPos < 0) + xPos = 0; + if (yPos < 0) + yPos = 0; + + // if picture + if (picture != null) + { + if (xPos >= picture.getWidth()) + xPos = picture.getWidth() - 1; + if (yPos >= picture.getHeight()) + yPos = picture.getHeight() - 1; + Graphics g = picture.getGraphics(); + paintComponent(g); + } + else if (modelDisplay != null) + { + if (xPos >= modelDisplay.getWidth()) + xPos = modelDisplay.getWidth() - 1; + if (yPos >= modelDisplay.getHeight()) + yPos = modelDisplay.getHeight() - 1; + modelDisplay.modelChanged(); + } + } + + /** + * Method to move the turtle foward 100 pixels + */ + public void forward() { forward(100); } + + /** + * Method to move the turtle forward the given number of pixels + * @param pixels the number of pixels to walk forward in the heading direction + */ + public void forward(int pixels) + { + int oldX = xPos; + int oldY = yPos; + + // change the current position + xPos = oldX + (int) (pixels * Math.sin(Math.toRadians(heading))); + yPos = oldY + (int) (pixels * -Math.cos(Math.toRadians(heading))); + + // add a move from the old position to the new position to the pen + pen.addMove(oldX,oldY,xPos,yPos); + + // update the display to show the new line + updateDisplay(); + } + + /** + * Method to go backward by 100 pixels + */ + public void backward() + { + backward(100); + } + + /** + * Method to go backward a given number of pixels + * @param pixels the number of pixels to walk backward + */ + public void backward(int pixels) + { + forward(-pixels); + } + + /** + * Method to move to turtle to the given x and y location + * @param x the x value to move to + * @param y the y value to move to + */ + public void moveTo(int x, int y) + { + this.pen.addMove(xPos,yPos,x,y); + this.xPos = x; + this.yPos = y; + this.updateDisplay(); + } + + /** + * Method to turn left + */ + public void turnLeft() + { + this.turn(-90); + } + + /** + * Method to turn right + */ + public void turnRight() + { + this.turn(90); + } + + /** + * Method to turn the turtle the passed degrees + * use negative to turn left and pos to turn right + * @param degrees the amount to turn in degrees + */ + public void turn(double degrees) + { + this.heading = (heading + degrees) % 360; + this.updateDisplay(); + } + + /** + * Method to draw a passed picture at the current turtle + * location and rotation in a picture or model display + * @param dropPicture the picture to drop + */ + public synchronized void drop(Picture dropPicture) + { + Graphics2D g2 = null; + + // only do this if drawing on a picture + if (picture != null) + g2 = (Graphics2D) picture.getGraphics(); + else if (modelDisplay != null) + g2 = (Graphics2D) modelDisplay.getGraphics(); + + // if g2 isn't null + if (g2 != null) + { + + // save the current tranform + AffineTransform oldTransform = g2.getTransform(); + + // rotate to turtle heading and translate to xPos and yPos + g2.rotate(Math.toRadians(heading),xPos,yPos); + + // draw the passed picture + g2.drawImage(dropPicture.getImage(),xPos,yPos,null); + + // reset the tranformation matrix + g2.setTransform(oldTransform); + + // draw the pen + pen.paintComponent(g2); + } + } + + /** + * Method to paint the turtle + * @param g the graphics context to paint on + */ + public synchronized void paintComponent(Graphics g) + { + // cast to 2d object + Graphics2D g2 = (Graphics2D) g; + + // if the turtle is visible + if (visible) + { + // save the current tranform + AffineTransform oldTransform = g2.getTransform(); + + // rotate the turtle and translate to xPos and yPos + g2.rotate(Math.toRadians(heading),xPos,yPos); + + // determine the half width and height of the shell + int halfWidth = (int) (width/2); // of shell + int halfHeight = (int) (height/2); // of shell + int quarterWidth = (int) (width/4); // of shell + int thirdHeight = (int) (height/3); // of shell + int thirdWidth = (int) (width/3); // of shell + + // draw the body parts (head) + g2.setColor(bodyColor); + g2.fillOval(xPos - quarterWidth, + yPos - halfHeight - (int) (height/3), + halfWidth, thirdHeight); + g2.fillOval(xPos - (2 * thirdWidth), + yPos - thirdHeight, + thirdWidth,thirdHeight); + g2.fillOval(xPos - (int) (1.6 * thirdWidth), + yPos + thirdHeight, + thirdWidth,thirdHeight); + g2.fillOval(xPos + (int) (1.3 * thirdWidth), + yPos - thirdHeight, + thirdWidth,thirdHeight); + g2.fillOval(xPos + (int) (0.9 * thirdWidth), + yPos + thirdHeight, + thirdWidth,thirdHeight); + + + // draw the shell + g2.setColor(getShellColor()); + g2.fillOval(xPos - halfWidth, + yPos - halfHeight, width, height); + + // draw the info string if the flag is true + if (showInfo) + drawInfoString(g2); + + // reset the tranformation matrix + g2.setTransform(oldTransform); + } + + // draw the pen + pen.paintComponent(g); + } + + /** + * Method to draw the information string + * @param g the graphics context + */ + public synchronized void drawInfoString(Graphics g) + { + g.setColor(infoColor); + g.drawString(this.toString(),xPos + (int) (width/2),yPos); + } + + /** + * Method to return a string with informaiton + * about this turtle + * @return a string with information about this object + */ + public String toString() + { + return this.name + " turtle at " + this.xPos + ", " + + this.yPos + " heading " + this.heading + "."; + } + + } // end of class + import java.util.*; + import java.awt.*; + + /** + * Class that represents a turtle which is similar to a Logo turtle. + * This class inherts from SimpleTurtle and is for students + * to add methods to. + * + * Copyright Georgia Institute of Technology 2004 + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class Turtle extends SimpleTurtle + { + ////////////////// constructors /////////////////////// + + /** Constructor that takes the x and y and a picture to + * draw on + * @param x the starting x position + * @param y the starting y position + * @param picture the picture to draw on + */ + public Turtle (int x, int y, Picture picture) + { + // let the parent constructor handle it + super(x,y,picture); + } + + /** Constructor that takes the x and y and a model + * display to draw it on + * @param x the starting x position + * @param y the starting y position + * @param modelDisplayer the thing that displays the model + */ + public Turtle (int x, int y, + ModelDisplay modelDisplayer) + { + // let the parent constructor handle it + super(x,y,modelDisplayer); + } + + /** Constructor that takes the model display + * @param modelDisplay the thing that displays the model + */ + public Turtle (ModelDisplay modelDisplay) + { + // let the parent constructor handle it + super(modelDisplay); + } + + /** + * Constructor that takes a picture to draw on + * @param p the picture to draw on + */ + public Turtle (Picture p) + { + // let the parent constructor handle it + super(p); + } + + /////////////////// methods /////////////////////// + + + public static void main(String[] args) + { + World earth = new World(); + Turtle t1 = new Turtle(earth); + t1.forward(); + } + + } // this is the end of class Turtle, put all new methods before this + /** + * https://github.com/ha-shine/Giffer + */ + import java.awt.Graphics2D; + import java.awt.Image; + import java.awt.image.BufferedImage; + import java.io.File; + import java.io.IOException; + import java.util.Iterator; + + import javax.imageio.IIOException; + import javax.imageio.IIOImage; + import javax.imageio.ImageIO; + import javax.imageio.ImageTypeSpecifier; + import javax.imageio.ImageWriter; + import javax.imageio.metadata.IIOInvalidTreeException; + import javax.imageio.metadata.IIOMetadata; + import javax.imageio.metadata.IIOMetadataNode; + import javax.imageio.stream.ImageOutputStream; + + /* + * Giffer is a simple java class to make my life easier in creating gif images. + * + * Usage : + * There are two methods for creating gif images + * To generate from files, just pass the array of filename Strings to this method + * Giffer.generateFromFiles(String[] filenames, String output, int delay, boolean loop) + * + * Or as an alternative you can use this method which accepts an array of BufferedImage + * Giffer.generateFromBI(BufferedImage[] images, String output, int delay, boolean loop) + * + * output is the name of the output file + * delay is time between frames, accepts hundredth of a time. Yeah it's weird, blame Oracle + * loop is the boolean for whether you want to make the image loopable. + */ + + public abstract class Giffer { + + // Generate gif from an array of filenames + // Make the gif loopable if loop is true + // Set the delay for each frame according to the delay (ms) + // Use the name given in String output for output file + public static void generateFromFiles(String[] filenames, String output, int delay, boolean loop) + throws IIOException, IOException + { + int length = filenames.length; + BufferedImage[] img_list = new BufferedImage[length]; + + for (int i = 0; i < length; i++) + { + BufferedImage img = ImageIO.read(new File(filenames[i])); + img_list[i] = img; + } + + generateFromBI(img_list, output, delay, loop); + } + + // Generate gif from BufferedImage array + // Make the gif loopable if loop is true + // Set the delay for each frame according to the delay, 100 = 1s + // Use the name given in String output for output file + public static void generateFromBI(BufferedImage[] images, String output, int delay, boolean loop) + throws IIOException, IOException + { + int maxWidth = 0; + int maxHeight = 0; + ImageWriter gifWriter = getWriter(); + ImageOutputStream ios = getImageOutputStream(output); + IIOMetadata metadata = getMetadata(gifWriter, delay, loop); + + //Get bigger Width and Height + for (BufferedImage img: images) + { + if(img.getHeight() > maxHeight){ + maxHeight = img.getHeight(); + } + if(img.getWidth() > maxWidth){ + maxWidth = img.getWidth(); + } + } + + gifWriter.setOutput(ios); + gifWriter.prepareWriteSequence(null); + for (BufferedImage img: images) + { + BufferedImage dimg = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_ARGB); + Image tmp = img.getScaledInstance(img.getWidth(), img.getHeight(), Image.SCALE_DEFAULT); + Graphics2D g2d = dimg.createGraphics(); + int centerWidth = (maxWidth / 2) - (img.getWidth()/2) ; + g2d.drawImage(tmp, centerWidth, 0, null); + g2d.dispose(); + + IIOImage temp = new IIOImage(dimg, null, metadata); + gifWriter.writeToSequence(temp, null); + } + + gifWriter.endWriteSequence(); + } + + // Retrieve gif writer + private static ImageWriter getWriter() throws IIOException + { + Iterator itr = ImageIO.getImageWritersByFormatName("gif"); + if(itr.hasNext()) + return (ImageWriter)itr.next(); + + throw new IIOException("GIF writer doesn't exist on this JVM!"); + } + + // Retrieve output stream from the given file name + private static ImageOutputStream getImageOutputStream(String output) throws IOException + { + File outfile = new File(output); + return ImageIO.createImageOutputStream(outfile); + } + + // Prepare metadata from the user input, add the delays and make it loopable + // based on the method parameters + private static IIOMetadata getMetadata(ImageWriter writer, int delay, boolean loop) + throws IIOInvalidTreeException + { + // Get the whole metadata tree node, the name is javax_imageio_gif_image_1.0 + // Not sure why I need the ImageTypeSpecifier, but it doesn't work without it + ImageTypeSpecifier img_type = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB); + IIOMetadata metadata = writer.getDefaultImageMetadata(img_type, null); + String native_format = metadata.getNativeMetadataFormatName(); + IIOMetadataNode node_tree = (IIOMetadataNode)metadata.getAsTree(native_format); + + // Set the delay time you can see the format specification on this page + // https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/gif_metadata.html + IIOMetadataNode graphics_node = getNode("GraphicControlExtension", node_tree); + graphics_node.setAttribute("delayTime", String.valueOf(delay)); + graphics_node.setAttribute("disposalMethod", "none"); + graphics_node.setAttribute("userInputFlag", "FALSE"); + + if(loop) + makeLoopy(node_tree); + + metadata.setFromTree(native_format, node_tree); + + return metadata; + } + + // Add an extra Application Extension node if the user wants it to be loopable + // I am not sure about this part, got the code from StackOverflow + // TODO: Study about this + private static void makeLoopy(IIOMetadataNode root) + { + IIOMetadataNode app_extensions = getNode("ApplicationExtensions", root); + IIOMetadataNode app_node = getNode("ApplicationExtension", app_extensions); + + app_node.setAttribute("applicationID", "NETSCAPE"); + app_node.setAttribute("authenticationCode", "2.0"); + app_node.setUserObject(new byte[]{ 0x1, (byte) (0 & 0xFF), (byte) ((0 >> 8) & 0xFF)}); + + app_extensions.appendChild(app_node); + root.appendChild(app_extensions); + } + + // Retrieve the node with the name from the parent root node + // Append the node if the node with the given name doesn't exist + private static IIOMetadataNode getNode(String node_name, IIOMetadataNode root) + { + IIOMetadataNode node = null; + + for (int i = 0; i < root.getLength(); i++) + { + if(root.item(i).getNodeName().compareToIgnoreCase(node_name) == 0) + { + node = (IIOMetadataNode) root.item(i); + return node; + } + } + + // Append the node with the given name if it doesn't exist + node = new IIOMetadataNode(node_name); + root.appendChild(node); + + return node; + } + } + import javax.swing.*; + import java.util.List; + import java.util.ArrayList; + import java.util.Iterator; + import java.util.Observer; + import java.awt.*; + + import java.net.*; + import java.io.*; + // import javax.xml.bind.DatatypeConverter; + // Using java.util.Base64 instead of javax.xml.bind + import java.util.Base64; + import javax.imageio.*; + import java.awt.image.*; + import javax.imageio.stream.*; + + + /** + * Class to represent a 2d world that can hold turtles and + * display them + * + * Copyright Georgia Institute of Technology 2004 + * @author Barb Ericson ericson@cc.gatech.edu + */ + @SuppressWarnings("unchecked") + public class World implements ModelDisplay + { + ////////////////// fields /////////////////////// + + /** should automatically repaint when model changed */ + private boolean autoRepaint = true; + + /** the background color for the world */ + private Color background = Color.white; + + /** the width of the world */ + private int width = 640; + + /** the height of the world */ + private int height = 480; + + /** the list of turtles in the world */ + private List turtleList = new ArrayList(); + + /** background picture */ + private Picture picture = null; + + /* All world changes*/ + private List worldHistory = new ArrayList(); + + + ////////////////// the constructors /////////////// + + /** + * Constructor that takes no arguments + */ + public World() + { + // set up the world and make it visible + initWorld(true); + } + + /** + * Constructor that takes a boolean to + * say if this world should be visible + * or not + * @param visibleFlag if true will be visible + * else if false will not be visible + */ + public World(boolean visibleFlag) + { + initWorld(visibleFlag); + } + + /** + * Constructor that takes a width and height for this + * world + * @param w the width for the world + * @param h the height for the world + */ + public World(int w, int h) + { + width = w; + height = h; + + // set up the world and make it visible + initWorld(true); + } + + ///////////////// methods /////////////////////////// + + /** + * Method to initialize the world + * @param visibleFlag the flag to make the world + * visible or not + */ + private void initWorld(boolean visibleFlag) + { + // create the background picture + picture = new Picture(width,height); + this.modelChanged(); + } + + /** + * Method to get the graphics context for drawing on + * @return the graphics context of the background picture + */ + public Graphics getGraphics() { return picture.getGraphics(); } + + /** + * Method to clear the background picture + */ + public void clearBackground() { picture = new Picture(width,height); } + + /** + * Method to get the background picture + * @return the background picture + */ + public Picture getPicture() { return picture; } + + /** + * Method to set the background picture + * @param pict the background picture to use + */ + public void setPicture(Picture pict) { picture = pict; } + + /** + * Method to paint this component + * @param g the graphics context + */ + public synchronized void paintComponent(Graphics g) + { + Turtle turtle = null; + + // draw the background image + g.drawImage(picture.getImage(),0,0,null); + + // loop drawing each turtle on the background image + Iterator iterator = turtleList.iterator(); + while (iterator.hasNext()) + { + turtle = (Turtle) iterator.next(); + turtle.paintComponent(g); + } + } + + /** + * Metod to get the last turtle in this world + * @return the last turtle added to this world + */ + public Turtle getLastTurtle() + { + return (Turtle) turtleList.get(turtleList.size() - 1); + } + + + /** + * Method to add a model to this model displayer + * @param model the model object to add + */ + public void addModel(Object model) + { + turtleList.add((Turtle) model); + } + + /** + * Method to check if this world contains the passed + * turtle + * @return true if there else false + */ + public boolean containsTurtle(Turtle turtle) + { + return (turtleList.contains(turtle)); + } + + /** + * Method to remove the passed object from the world + * @param model the model object to remove + */ + public void remove(Object model) + { + turtleList.remove(model); + } + + /** + * Method to get the width in pixels + * @return the width in pixels + */ + public int getWidth() { return width; } + + /** + * Method to get the height in pixels + * @return the height in pixels + */ + public int getHeight() { return height; } + + /** + * Method that allows the model to notify the display + */ + public void modelChanged() + { + Picture p = new Picture(this.width, this.height); + this.paintComponent(p.getGraphics()); + this.worldHistory.add(p); + } + + /** + * Method to set the automatically repaint flag + * @param value if true will auto repaint + */ + public void setAutoRepaint(boolean value) { autoRepaint = value; } + + /** + * Method to show the frame + */ + public void show() + { + this.show(false); + } + + public void show(boolean showHistory) { + this.paintComponent(this.picture.getGraphics()); + if(showHistory) { + try { + BufferedImage[] images = new BufferedImage[this.worldHistory.size()]; + for(int i = 0; i < this.worldHistory.size(); i++) { + images[i] = ((Picture) this.worldHistory.get(i)).getBufferedImage(); + } + Giffer.generateFromBI(images, "history.gif", 100, false); + + File history = new File("history.gif"); + + URL url = history.toURI().toURL(); + + byte[] imageBytes = downloadUrl(url); + String result = + //DatatypeConverter.printBase64Binary(imageBytes); + //BH: using java.util.Base64 instead of javax.xml.bind.DataTypeConverter + Base64.getEncoder().encodeToString(imageBytes); + + System.gc(); + history.delete(); + double rand = Math.random(); + System.out.println("<img src=\'data:image/gif;base64," + result + "\'/>"); + + } catch (IOException e) { + e.printStackTrace(); + } + + } else { + this.picture.show(); + } + } + + private byte[] downloadUrl(URL toDownload) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + try { + byte[] chunk = new byte[4096]; + int bytesRead; + InputStream stream = toDownload.openStream(); + + while ((bytesRead = stream.read(chunk)) > 0) { + outputStream.write(chunk, 0, bytesRead); + } + //toDownload.close(); + + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + return outputStream.toByteArray(); + } + + /** + * Method to get the list of turtles in the world + * @return a list of turtles in the world + */ + public List getTurtleList() + { return turtleList;} + + /** + * Method to get an iterator on the list of turtles + * @return an iterator for the list of turtles + */ + public Iterator getTurtleIterator() + { return turtleList.iterator();} + + /** + * Method that returns information about this world + * in the form of a string + * @return a string of information about this world + */ + public String toString() + { + return "A " + getWidth() + " by " + getHeight() + + " world with " + turtleList.size() + " turtles in it."; + } + + } // end of World class diff --git a/tests/test_course_1/_sources/index.rst b/tests/test_course_1/_sources/index.rst index 0c8d55dc8..73d20ff12 100644 --- a/tests/test_course_1/_sources/index.rst +++ b/tests/test_course_1/_sources/index.rst @@ -11,6 +11,7 @@ This book generates data for use with the test suite. lp_demo.py lp_demo-test.py selectquestion + activecode ActiveCode @@ -26,27 +27,6 @@ ActiveCode print(total) -.. activecode:: test_activecode_2 - :nocodelens: - :autograde: unittest - - Fix the following code so that it always correctly adds two numbers. - ~~~~ - def add(a,b): - return 4 - - ==== - from unittest.gui import TestCaseGui - - class myTests(TestCaseGui): - - def testOne(self): - self.assertEqual(add(2,2),4,"A feedback string when the test fails") - self.assertAlmostEqual(add(2.0,3.0), 5.0, 5, "Try adding your parameters") - - myTests().main() - - Clickable Area ============== .. clickablearea:: test_clickablearea_1 diff --git a/tests/test_course_1/_sources/selectquestion.rst b/tests/test_course_1/_sources/selectquestion.rst index 98dd729d1..9ced88f17 100644 --- a/tests/test_course_1/_sources/selectquestion.rst +++ b/tests/test_course_1/_sources/selectquestion.rst @@ -58,5 +58,9 @@ The following spreadsheet ``selectquestion`` components are commented out, since :fromid: test_dnd_1 +.. selectquestion:: select_question_15 + :fromid: test_activecode_2 + + .. selectquestion:: select_question_20 :fromid: test_short_answer_1 diff --git a/tests/test_runestone_components.py b/tests/test_runestone_components.py index 4a760590c..b31bdfe3c 100644 --- a/tests/test_runestone_components.py +++ b/tests/test_runestone_components.py @@ -17,6 +17,7 @@ # ------------------- from polling2 import poll import pytest +from runestone.activecode.test import test_activecode from runestone.clickableArea.test import test_clickableArea from runestone.dragndrop.test import test_dragndrop from runestone.fitb.test import test_fitb @@ -88,9 +89,40 @@ def selenium_utils_user_2(selenium_utils_user): return selenium_utils_user +# A fixture for active code server-side testing. +@pytest.fixture +def selenium_utils_user_ac(selenium_utils_user): + selenium_utils_user.get_book_url("activecode.html") + return selenium_utils_user + + # Tests # ===== # +# Active code +# ----------- +def test_activecode_1(selenium_utils_user_ac, runestone_db): + db = runestone_db + + def ac_check_fields(index, div_id): + row = get_answer(db, db.code.acid == div_id, index + 1)[index] + assert row.timestamp - datetime.datetime.now() < datetime.timedelta(seconds=5) + assert row.acid == div_id + assert row.sid == selenium_utils_user_ac.user.username + assert row.course_id == selenium_utils_user_ac.user.course.course_id + return row + + test_activecode.test_history(selenium_utils_user_ac) + row = ac_check_fields(0, "test_activecode_2") + assert row.emessage == "success" + assert row.code == "print('Goodbye')" + assert row.grade == None + assert row.comment == None + assert row.language == "python" + + # TODO: There are a lot more activecode tests that could be easily ported! + + # ClickableArea # ------------- def test_clickable_area_1(selenium_utils_user_1, runestone_db): @@ -356,6 +388,10 @@ def test_selectquestion_7(selenium_utils_user_2, runestone_db): test_dnd_1(selenium_utils_user_2, runestone_db) +def test_selectquestion_8(selenium_utils_user_2, runestone_db): + test_activecode_1(selenium_utils_user_2, runestone_db) + + def test_selectquestion_20(selenium_utils_user_2, runestone_db): test_short_answer_1(selenium_utils_user_2, runestone_db)