package byow.TileEngine;
import java.awt.Color;
import java.util.Arrays;
import java.util.Random;
import edu.princeton.cs.introcs.StdDraw;
import byow.Core.RandomUtils;
/**
* The TETile object is used to represent a single tile in your world. A 2D array of tiles make up a
* board, and can be drawn to the screen using the TERenderer class.
*
* All TETile objects must have a character, textcolor, and background color to be used to represent
* the tile when drawn to the screen. You can also optionally provide a path to an image file of an
* appropriate size (16×16) to be drawn in place of the unicode representation. If the image path
* provided cannot be found, draw will fallback to using the provided character and color
* representation, so you are free to use image tiles on your own computer.
*
* The provided TETile is immutable, i.e. none of its instance variables can change. You are welcome
* to make your TETile class mutable, if you prefer.
*/
public class TETile {
private final char character; // Do not rename character or the autograder will break.
private final Color textColor;
private final Color backgroundColor;
private final String description;
private final String filepath;
/**
* Full constructor for TETile objects.
* @param character The character displayed on the screen.
* @param textColor The color of the character itself.
* @param backgroundColor The color drawn behind the character.
* @param description The description of the tile, shown in the GUI on hovering over the tile.
* @param filepath Full path to image to be used for this tile. Must be correct size (16×16)
*/
public TETile(char character, Color textColor, Color backgroundColor, String description,
String filepath) {
this.character = character;
this.textColor = textColor;
this.backgroundColor = backgroundColor;
this.description = description;
this.filepath = filepath;
}
/**
* Constructor without filepath. In this case, filepath will be null, so when drawing, we
* will not even try to draw an image, and will instead use the provided character and colors.
* @param character The character displayed on the screen.
* @param textColor The color of the character itself.
* @param backgroundColor The color drawn behind the character.
* @param description The description of the tile, shown in the GUI on hovering over the tile.
*/
public TETile(char character, Color textColor, Color backgroundColor, String description) {
this.character = character;
this.textColor = textColor;
this.backgroundColor = backgroundColor;
this.description = description;
this.filepath = null;
}
/**
* Creates a copy of TETile t, except with given textColor.
* @param t tile to copy
* @param textColor foreground color for tile copy
*/
public TETile(TETile t, Color textColor) {
this(t.character, textColor, t.backgroundColor, t.description, t.filepath);
}
/**
* Draws the tile to the screen at location x, y. If a valid filepath is provided,
* we draw the image located at that filepath to the screen. Otherwise, we fall
* back to the character and color representation for the tile.
*
* Note that the image provided must be of the right size (16×16). It will not be
* automatically resized or truncated.
* @param x x coordinate
* @param y y coordinate
*/
public void draw(double x, double y) {
if (filepath != null) {
try {
StdDraw.picture(x + 0.5, y + 0.5, filepath);
return;
} catch (IllegalArgumentException e) {
// Exception happens because the file can’t be found. In this case, fail silently
// and just use the character and background color for the tile.
}
}
StdDraw.setPenColor(backgroundColor);
StdDraw.filledSquare(x + 0.5, y + 0.5, 0.5);
StdDraw.setPenColor(textColor);
StdDraw.text(x + 0.5, y + 0.5, Character.toString(character()));
}
/** Character representation of the tile. Used for drawing in text mode.
* @return character representation
*/
public char character() {
return character;
}
/**
* Description of the tile. Useful for displaying mouseover text or
* testing that two tiles represent the same type of thing.
* @return description of the tile
*/
public String description() {
return description;
}
/**
* Creates a copy of the given tile with a slightly different text color. The new
* color will have a red value that is within dr of the current red value,
* and likewise with dg and db.
* @param t the tile to copy
* @param dr the maximum difference in red value
* @param dg the maximum difference in green value
* @param db the maximum difference in blue value
* @param r the random number generator to use
*/
public static TETile colorVariant(TETile t, int dr, int dg, int db, Random r) {
Color oldColor = t.textColor;
int newRed = newColorValue(oldColor.getRed(), dr, r);
int newGreen = newColorValue(oldColor.getGreen(), dg, r);
int newBlue = newColorValue(oldColor.getBlue(), db, r);
Color c = new Color(newRed, newGreen, newBlue);
return new TETile(t, c);
}
private static int newColorValue(int v, int dv, Random r) {
int rawNewValue = v + RandomUtils.uniform(r, -dv, dv + 1);
// make sure value doesn’t fall outside of the range 0 to 255.
int newValue = Math.min(255, Math.max(0, rawNewValue));
return newValue;
}
/**
* Converts the given 2D array to a String. Handy for debugging.
* Note that since y = 0 is actually the bottom of your world when
* drawn using the tile rendering engine, this print method has to
* print in what might seem like backwards order (so that the 0th
* row gets printed last).
* @param world the 2D world to print
* @return string representation of the world
*/
public static String toString(TETile[][] world) {
int width = world.length;
int height = world[0].length;
StringBuilder sb = new StringBuilder();
for (int y = height – 1; y >= 0; y -= 1) {
for (int x = 0; x < width; x += 1) {
if (world[x][y] == null) {
throw new IllegalArgumentException("Tile at position x=" + x + ", y=" + y
+ " is null.");
}
sb.append(world[x][y].character());
}
sb.append('\n');
}
return sb.toString();
}
/**
* Makes a copy of the given 2D tile array.
* @param tiles the 2D array to copy
**/
public static TETile[][] copyOf(TETile[][] tiles) {
if (tiles == null) {
return null;
}
TETile[][] copy = new TETile[tiles.length][];
int i = 0;
for (TETile[] column : tiles) {
copy[i] = Arrays.copyOf(column, column.length);
i += 1;
}
return copy;
}
}