CS 1 (Fall 2024) Project 06: Critters

This project provides an open-ended problem and gives you a chance to use LLMs to supplement your coding!

Introduction

There are two reasons for this project:

  1. Provide a smooth transition from coding in Python to coding in Java
  2. Provide an introduction on how to use LLMs responsibly while coding

We believe these goals dovetail pretty nicely. As you transition to Java, there will be a lot of syntax that you aren’t familiar with. This is something ChatGPT excels at helping with!! As discussed in class, we want you to come out of CS 1 with an understanding that LLMs are (1) super helpful if used responsibly, and (2) super dangerous if used irresponsibly.

LLM Policy for this Project

The LLM Policy for this project is quite lax. You can ask ChatGPT any prompt you like, but you must use the interface on Ed to do so. Since our goal is to teach you basic prompt engineering on this project, we need access to your queries; so, we can provide feedback and help you! (To be honest, we’re also super curious how y’all choose to use LLM’s to complete the project…)

Here are some queries you might try:

Installation and Beginning a Java Project

Running tests will be slightly different in Java. You’ll need to use the beaker on the left instead of the beaker in the top right corner. From there, you can run individual tests for the basic classes. If anything goes wrong, the error message will be shown within the test file (you might need to scroll around in the window to see all the information). Feel free to come to OH if anything is confusing about the tests.

Part 0: LLMs are NOT Magic

For this project, you are only allowed to make LLM queries through Ed Discussion’s Interface by making a post in the LLM category, responding to something ChatGPT said in a post, or adding a comment to an LLM megathread.

Critters: Our Testing Ground

For the remainder of this project, we will be working in a simulation of ``critters’’. You will implement several classes that will be used in a client program provided to you which represents a graphical simulation of a 2D world of animals. You will write classes that define the behavior of several types of critters, each of which moves and behaves in different ways.

The critter world is divided into cells with integer coordinates. The upper-left cell has coordinates (0, 0); x increases to the right and y increases downward. The world has a finite size, but it wraps around in all four directions (e.g., moving east from the right edge brings you back to the left edge).

In this project, you will be forced to consider carefully what information you need to track the current state of your critter, in the form of fields, in order to make your critters do what you want. This is because your objects are part of a larger system. You might want your critters to make several moves at once using a loop, but you can’t. Critters can only make one move at a time, and only when the simulator asks. This experience may be frustrating because it is a new way of programming, but it is important. In most real-world projects, you will not be in control of the entire environment and will have to work with existing code that you cannot change.

While the amount and complexity of the code you write will be less than recent projects (since we want you to adjust to Java), this will involve more careful use of classes. You are given a base class called Critter in Critter.java, which defines the default behavior of all critters.

Each critter you implement will be a type of Critter and override some of the default behaviors.

Understanding Critters

Before you can start implementing your critters, it is important you understand the basic functionality of a critter. Below, we discuss what the most important methods of the Critter class represent. You can see what the Critter class does for each of these by default in Critter.java.

public Direction getMove()

The simulation takes place in a series of rounds, with each critter making a single move in each round. Critters specify the direction they wish to move by returning one of the values for the Direction enum - Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST and Direction.CENTER - from this method. These represent what you would expect, with Direction.CENTER representing the critter choosing to stay in the same cell.


public Attack fight(String opponent)

As the simulation runs, critters may collide by moving onto the same location. When two critters collide, if they are from different species, they fight. Here, each critter has a string representation (which you will read more about below), and you are given the string representation of your opponent as a parameter. Each critter chooses one of the 3 values of the Attack enum - Attack.ROAR, Attack.POUNCE, or Attack.SCRATCH. Each attack is strong against one other attack (e.g. roar beats scratch) and weak against one. ROAR beats SCRATCH which beats POUNCE which beats ROAR. If it helps you remember, roar, scratch, pounce are equivalent to rock, scissors, paper. The winning critter survives and the losing critter dies and is removed from the game. Ties are decided randomly. This method returns which of the 3 attack types the critter chooses depending on the opponent it collides with.


public boolean eat()

The simulation world also contains food (represented by the period character) for the critters to eat. Food is initially placed in the world randomly, and new food is gradually added over time. As a critter moves, it may encounter food, in which case the simulator will ask the critter, through this method, whether it wants to eat. This method returns true to eat or false to not eat.


public Color getColor()

Called each round to determine color to display critter as.


public String toString()

Called each round to determine text to display critter as (this is also the string representation of the critter which is given to opponents when in a fight).


The Stone Critter

An example critter which extends the Critter class called Stone is given to you in Stone.java for you to see how you may extend a class in Java and overwrite some of its methods. When you override a method, be sure to use the exact same name and parameters. In particular, you cannot add parameters. A Stone is always displayed as a gray capital “S”, never moves or eats and always roars in a fight.Notice how the Stone class does not implement the methods for which it is using the default behavior. Your critter classes will look similar to this, but will be more sophisticated, and may include fields and constructors.

Part 1: Required Critters

In this part, you will practice writing Critter’s that are on the simpler side so that you can ultimately write the Assassin Critter. Note that you are welcome to ask ChatGPT for the solutions to these Critter’s if you think that is a more efficient way of understanding what they should do.

Part 2: The Assassin

In the final part of this project, you will write a custom critter that always tries to meet a provided metric. To write a critter that succeeds, you need to know a few more things about how the simulation works:

The Assassin’s Goal

The Assassin critters must band together as a team to ensure that their total score always converges to exactly 85. Once the overall score hits the target, it may wiggle around a bit, but it should always stabilize back at the target.

Grading Thresholds

Grading on this project will work as follows: