In this lab, we\'ll be writing a class hierarchy of Emoji. Here is a UML diagram
ID: 3784930 • Letter: I
Question
In this lab, we'll be writing a class hierarchy of Emoji. Here is a UML diagram of the classes we'll be writing:
Emoji and Face Emoji are abstract classes because they don't have enough information to be useful on their own.
Here's a description of what each class should contain:
Emoji (abstract class):
member variables for position and size of the emoji
constructor taking x, y, size
abstract void draw(). We can't implement this method yet, so it's abstract, but all emoji that inherit from it must have a draw method
FaceEmoji (abstract class):
constructor
void draw() //this will draw the yellow circle and black eyes of the face, but it doesn't have enough information to draw the mouth
SmileyFaceEmoji:
constructor
void draw() //use StdDraw.arc to draw the smiling face
FrowningFaceEmoji:
constructor
void draw() //like smiley face, but sadder
ClockEmoji:
constructor (taking an extra int param for the hour the clock is set to)
void draw() //draw a circle around the border and an "hour hand" line out from the center that shows the correct time
Driver (with main)
In main, read from the emojiInputs.txt file. The file contains information about a grid of emoji. The file starts with the number of rows, then the number of columns.
Then, it lists the emoji that should fill in the grid. "smile" means the emoji should be a SmileyFaceEmoji, "frown" means a FrowningFaceEmoji, and "clock" means ClockEmoji and will always be followed by an integer representing the hour hand of the clock.
Each emoji should be 100 pixels x 100 pixels.
Test your code with a text file containing "4
4
smile
frown
smile
clock 4
clock 8
frown
smile
clock 3
clock 12
clock 10
smile
smile
smile
frown
frown
frown"
Your program should produce output similar to this:
Once you have that working, we're going to add a couple of additional methods and test them.
Add a tick() method to the ClockEmoji class that adds one to the hour (it should wrap around at 12).'
Add an additional boolean to the FaceEmoji class named winking. Set it to false in the constructor.
Modify the draw method of your FaceEmoji class so that if it is winking, one of the eyes is drawn as a line instead of a circle.
Add a wink() method to the FaceEmoji class to toggle (flip the value) of your winking member variable.
In main, animate your emoji by calling wink() on the faces and tick() on the clocks and then drawing them. You'll need to use instanceof and typecasts to accomplish this. You should call StdDraw.show(500) inside your animation loop so that they don't update too quickly.
Hopefully you can tell that this isn't the best way to implement animated emoji. We're going to "refactor" our code in order to improve it.
Add a new abstract method named animate() to the Emoji class, then override it in the FaceEmoji and ClockEmoji classes to call the appropriate methods (wink and tick). Comment out the code in main that calls tick() and wink(), and then add code to use the new animate() method. By modifying our program design to add a new abstract method, we've significantly simplified the code.
UML:
Output:
Explanation / Answer
EmojiDriver.java
import java.io.FileInputStream;
import java.util.Scanner;
import edu.princeton.cs.introcs.StdDraw;
public class EmojiDriver {
public static void main(String[] args) throws Exception{
//Read the file
Scanner file = new Scanner( new FileInputStream("emoji1.txt"));
int rows = file.nextInt();
int columns = file.nextInt();
//Create the array
Emoji[][] emoji = new Emoji[rows][columns];
String scan;
//Set the canvas
int size = 125;
int xScale = columns*size;
int yScale = rows*size;
double radius;
if (columns > rows) {
radius = (0.5*xScale)/columns;
} else {
radius = (0.5*yScale)/rows;
}
StdDraw.setCanvasSize(xScale, yScale);
StdDraw.setXscale(0, xScale);
StdDraw.setYscale(yScale, 0);
//Fill the array from text file
for (int r = 0; r < rows; r++){
for (int c = 0; c < columns; c++){
scan = file.next();
if (scan.equals("clock")) {
String word = file.next();
String m = file.next();
int hour = Integer.parseInt(word);
int min = Integer.parseInt(m);
emoji[r][c] = new ClockEmoji(radius + 2*c*radius, radius + 2*r*radius, radius, hour, min);
} else if (scan.equals("smile")) {
emoji[r][c] = new SmileyFaceEmoji(radius + 2*c*radius, radius + 2*r*radius, radius, true);
} else if (scan.equals("frown")) {
emoji[r][c] = new FrowningFaceEmoji(radius + 2*c*radius, radius + 2*r*radius, radius, true);
}
}
}
//Draw and animate the array
while(true) {
StdDraw.clear();
for (int r = 0; r < rows; r++) {
for (int c = 0; c < columns; c++) {
emoji[r][c].draw();
emoji[r][c].animate();
}
}
StdDraw.show(500);
}
}
}
ClockEmoji.java
import edu.princeton.cs.introcs.StdDraw;
public class ClockEmoji extends Emoji{
//Instance Variables
private int hour;
private int minute;
public ClockEmoji(double x, double y, double r, int hr, int min) {
super(x, y, r);
hour = hr;
minute = min;
}
public void draw() {
StdDraw.setPenRadius(0.005);
StdDraw.circle(getCenterX(), getCenterY(), getRadius());
StdDraw.line(getCenterX(), getCenterY(), getCenterX() + getRadius()*0.9*Math.cos((minute-15)*Math.PI/30), getCenterY() + getRadius()*0.9*Math.sin((minute-15)*Math.PI/30));
StdDraw.line(getCenterX(), getCenterY(), getCenterX() + getRadius()*0.7*Math.cos((hour-3)*Math.PI/6), getCenterY() + getRadius()*0.7*Math.sin((hour-3)*Math.PI/6));
}
public void animate() {
if (minute == 59) {
minute = 0;
hour++;
} else {
minute++;
}
}
}
Emoji.java
public abstract class Emoji {
//Instance Variables
private double centerX;
private double centerY;
private double radius;
//Constructor
public Emoji(double x, double y, double r) {
centerX = x;
centerY = y;
radius = r;
}
//Accessor Methods
public double getCenterX() {
return centerX;
}
public double getCenterY() {
return centerY;
}
public double getRadius() {
return radius;
}
//Abstract Methods
public abstract void draw();
public abstract void animate();
}
SmileyFaceEmoji.java
import edu.princeton.cs.introcs.StdDraw;
public class SmileyFaceEmoji extends FaceEmoji {
//Constructor
public SmileyFaceEmoji(double x, double y, double r, boolean wink) {
super(x, y, r, wink);
}
//Call FaceEmoji draw method and add a smile
public void draw(){
super.draw();
StdDraw.arc(getCenterX(), getCenterY() + (0.2)*getRadius(), getRadius() * 0.4, 180, 0);
}
}
FaceEmoji.java
import edu.princeton.cs.introcs.StdDraw;
public abstract class FaceEmoji extends Emoji{
//Instance Variables
private boolean isWinking;
//Constructor
public FaceEmoji(double x, double y, double r, boolean wink) {
super(x, y, r);
isWinking = wink;
}
//Draw a face with two eyes
public void draw(){
StdDraw.setPenColor(StdDraw.YELLOW);
StdDraw.filledCircle(getCenterX(), getCenterY(), getRadius());
StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.setPenRadius((0.00013)*getRadius());
StdDraw.filledCircle(getCenterX() + (0.25)* getRadius(), getCenterY() - (0.25)*getRadius(), getRadius()*(0.1));
if (isWinking){
StdDraw.arc(getCenterX() - (0.25)* getRadius(), getCenterY() - (0.25)*getRadius(), getRadius()*(0.1), 0, 180);
} else {
StdDraw.filledCircle(getCenterX() - (0.25)* getRadius(), getCenterY() - (0.25)*getRadius(), getRadius()*(0.1));
}
}
//Make one eye wink and unwink
public void animate() {
if (isWinking) {
isWinking = false;
} else {
isWinking = true;
}
}
}
FrowningFaceEmoji.java
import edu.princeton.cs.introcs.StdDraw;
public class FrowningFaceEmoji extends FaceEmoji{
//Constructor
public FrowningFaceEmoji(double x, double y, double r, boolean wink) {
super(x, y, r, wink);
}
//Call FaceEmoji draw method and add a frown
public void draw() {
super.draw();
StdDraw.arc(getCenterX(), getCenterY() + (0.5)*getRadius(), getRadius() * 0.4, 0, 180);
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.