Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
AAA_codegolf_catch_the_cat
Be aware that this consists of 2 packages. As gist does not support folders you have to make them yourself, the structure should look like this:
-main
-Controller.java
-Field.java
-MyFrame.java
-players
-Cat.java
-Catcher.java
-Player.java
-RandCat.java
-StupidFillCatcher.java
-StupidRightCat.java
When you participate you have to implement the Catcher or the Cat class. For running the game you just have to run 'Controller.java'. For a graphical representation of what is going on toggle the corresponding variable in the 'Controller.java' file. Further options are in 'MyFrame.java'.
package players;
/**
* @author The E
*/
import main.*;
public class Agamemnon implements Catcher {
boolean up = true;
public String getName() {
return "Agamemnon";
}
public int[] takeTurn(Field f) {
//First Make Line in column 1
for(int j = 0; j<f.SIZE; j++)
{
if(f.read(0, j)==Field.EMPTY)
{
return new int[]{0,j};
}
}
//Then in column SIZE/2
for(int j = 0; j<f.SIZE; j++)
{
if(f.read(f.SIZE/2, j)==Field.EMPTY)
{
return new int[]{f.SIZE/2,j};
}
}
//Then work out where the cat is
int left, right;
int cati = f.findCat()[0];
if(cati<f.SIZE/2)
{
left = 1;
right = f.SIZE/2-1;
}
else
{
left = f.SIZE/2+1;
right = f.SIZE-1;
}
while(right-left>1)
{
//If the cat is not in a two width column
//Split the area the cat is in in half
int middleColumn = (left+right)/2;
for(int j = 0; j<f.SIZE; j++)
{
if(f.read(middleColumn, j)==Field.EMPTY)
{
return new int[]{middleColumn,j};
}
}
//If we got here we had finished that column
//So update left and/or right
if(cati<middleColumn)
{
//he's left of the middle Column
right = middleColumn - 1;
}
else
{
//he's right of the middle Column
left = middleColumn+1;
}
//Repeat
}
//Otherwise try to trap the cat
//Make a line up and down on the opposite side of the cat
int catj = f.findCat()[1];
if(left!=right){
if(cati==left)
{
if(f.read(right, catj)==Field.EMPTY)
{
return new int[]{right, catj};
}
if(f.read(right, catj-1)==Field.EMPTY)
{
return new int[]{right, catj-1};
}
if(f.read(right, catj+1)==Field.EMPTY)
{
return new int[]{right, catj+1};
}
}
else
{
if(f.read(left, catj)==Field.EMPTY)
{
return new int[]{left, catj};
}
if(f.read(left, catj-1)==Field.EMPTY)
{
return new int[]{left, catj-1};
}
if(f.read(left, catj+1)==Field.EMPTY)
{
return new int[]{left, catj+1};
}
}
}
//Alternate between above and below
if(up)
{
up = !up;
if(f.read(cati, catj+1)==Field.EMPTY)
{
return new int[]{cati, catj+1};
}
}
up = !up;
if(f.read(cati, catj-1)==Field.EMPTY)
{
return new int[]{cati, catj-1};
}
return WasteGo(f);
}
private int[] WasteGo(Field f) {
for (int i = 0; i<f.SIZE;i++)
{
for(int j=0;j<f.SIZE;j++)
{
if(f.read(i,j)==Field.EMPTY)
{
return new int[]{i,j};
}
}
}
//Something drastic happened
return new int[]{0,0};
}
}
package players;
public interface Cat extends Player{
}
package players;
public interface Catcher extends Player {
}
package players;
/**
* @author randomra
*/
import main.Field;
import java.util.Arrays;
public class CloseCatcher implements Catcher {
public String getName() {
return "CloseCatcher";
}
final int[][] turns = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 },
{ 0, -1 }, { 1, -1 } };// all valid moves
final int turnCheck = 3;
public int[] takeTurn(Field f) {
int[] pos = f.findCat();
int[] bestMove = { 0, 1 };
int bestMoveCount = -1;
for (int[] t : turns) {
int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
int moveCount = free_count(currPos, turnCheck, f);
if (moveCount > bestMoveCount) {
bestMoveCount = moveCount;
bestMove = t;
}
}
int[] bestPos = { pos[0] + bestMove[0], pos[1] + bestMove[1] };
return bestPos;
}
private int free_count(int[] pos, int turnsLeft, Field f) {
if (f.isValidPosition(pos) || Arrays.equals(pos, f.findCat())) {
if (turnsLeft == 0) {
return 1;
}
int routeCount = 0;
for (int[] t : turns) {
int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
int moveCount = free_count(currPos, turnsLeft - 1, f);
routeCount += moveCount;
}
return routeCount;
}
return 0;
}
}
package main;
import players.*;
/**
* INSTRUCTIONS: Add your cat/class in the arrays in the methods getCats() or getCatchers
*/
public class Controller {
public static final int NUMBER_OF_GAMES = 100; //number of games per cat/catcher pair
public static final int FIELD_SIZE = 11; //standard 11x11
public static final long MAX_TURN_TIME = 200*1000000; // Nanoseconds per Turn (200ms)
public static final boolean PRINT_STEPS = !true; //graphical representation useful for debugging
public static final int STEP_DURATION = 200;//in ms only applies if PRINT_STEPS = true;
Cat[] cats;
Catcher[] catchers;
int[][][] results;
private MyFrame window;
/**
* Add your cat class in this array.
*/
public Cat[] getCats(){
return new Cat[] {new RandCat(),new StupidRightCat(), new SpiralCat(), new StraightCat(), new FreeCat()};
}
/**
* Add your catcher class in this array.
*/
public Catcher[] getCatchers(){
return new Catcher[] {/*new RandCatcher(),new StupidFillCatcher(),*/ new Achilles() /*, new Agamemnon()*/};
}
Controller(){
cats = getCats();
catchers = getCatchers();
results = new int[cats.length][catchers.length][NUMBER_OF_GAMES];
if (PRINT_STEPS){
window = new MyFrame(new Field(FIELD_SIZE));
}
}
/**
* Plays and evaluates the games
*/
public void playGames(){
System.out.println("Playing Games");
//for each pairing of cat/catcher
for(int i=0;i<cats.length;i++){
for(int j=0;j<catchers.length;j++){
for(int k=0; k < NUMBER_OF_GAMES; k++){
results[i][j][k] = playGame(cats[i],catchers[j]);
}
}
}
}
public int playGame(Cat cat, Catcher catcher){
//System.out.println("Playing a game:"+cat.getName()+" vs "+catcher.getName());
// new game
Field field = new Field(FIELD_SIZE);
if(PRINT_STEPS){
window.updateField(field);
}
int count = 0;
Field fieldCopy;//only pass copies of the field in order to prevent the submissions from manipulating data
long startTurnTime;
for(count=0; field.isFinished()==false; count++){//turn by turn
fieldCopy = new Field(field);
if(count%2==0){//catcher's turn
try {
startTurnTime = System.nanoTime();//measure time
int[] pos = catcher.takeTurn(fieldCopy);//check validity of turns and execute turns
// check time limit and validity
if(System.nanoTime() - startTurnTime < MAX_TURN_TIME && field.isValidPosition(pos)){
field.placeBucket(pos);
} else {
System.out.println(catcher.getName()+" is disqualified. Reason: Time");
return -10;
}
} catch(Throwable e){
System.out.println(catcher.getName()+" is disqualified. Reason: Exception/Error");
e.printStackTrace();
return -10;
}
} else {//cat's turn
try {
startTurnTime = System.nanoTime();//measure time
int[] move = cat.takeTurn(fieldCopy);
if(System.nanoTime() - startTurnTime < MAX_TURN_TIME && field.isValidMove(move)){
field.executeMove(move);
} else {
System.out.println(cat.getName()+" is disqualified. Reason: Time");
//int[] pos = field.findCat();
//System.out.println("Position was "+pos[0]+" , "+pos[1]);
//System.out.println("Move was "+move[0] + " , "+ move[1]);
return -1;
}
} catch(Throwable e){
System.out.println(cat.getName()+" is disqualified: Reason: Exception/Error");
e.printStackTrace();
return -1;
}
}//end catcher/cats turn
if(count > field.SIZE*field.SIZE*2){
System.out.println("Game ended with too many moves. Something went terribly wrong.");
return -100;
}
if(PRINT_STEPS){
System.out.println("Current State");
System.out.println(field.toString());
}
//GUI for animation
if(PRINT_STEPS){
window.repaint();
try {
Thread.sleep(STEP_DURATION); //1000 milliseconds is one second.
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}//for (turns)
return count;
}//end of playGame()
public void printTable(){
//print catcher ids
System.out.println("Legend:");
System.out.println("Catchers:");
for(int j = 0; j < catchers.length; j++){
System.out.println("X"+j+" : "+catchers[j].getName());
}
//print cats ids
System.out.println("Cats:");
for(int j = 0; j < cats.length; j++){
System.out.println("Y"+j+" : "+cats[j].getName());
}
System.out.println("Results of the games: (a number for the number of steps, or the player who was disqualified first)");
//create table header
System.out.println("");
for(int j = 0; j < catchers.length; j++){
System.out.print("\tX"+j+":");
}
//store cart
int[][] chart = new int[cats.length][catchers.length];
int sum = 0;
//looping over cats (each cat a row)
for(int i = 0; i < cats.length; i++){
System.out.println("");
System.out.print("Y"+i+":\t");
//looping over catchers (each catcher a column)
for(int j = 0; j < catchers.length; j++){
sum = 0;
for(int k = 0; k < Controller.NUMBER_OF_GAMES; k++){
sum += results[i][j][k];
//take care of disqualified
if(results[i][j][k] == -1){//cats
sum = -1;
break;
} else if(results[i][j][k] == -10){//catchers
sum = -10;
break;
} else if (results[i][j][k] == -100){//Error
sum = -100;
break;
}
}
//display the first disqualified
if(sum == -10){
System.out.print("X"+j+"\t");
} else if(sum == -1){
System.out.print("Y"+i+"\t");
} else if (sum == -100) {
System.out.print("Err"+"\t");
} else {
System.out.print(sum+"\t");
chart[i][j] = sum;
}
}
}
//displaying the scores of each players divided into sections:
System.out.println("\n\nScore chart:");
//cats
System.out.print("Total Score Cats:");
for(int i = 0; i < cats.length; i++){
System.out.println("");
System.out.print("Y"+i+":\t");
//looping over catchers (each catcher a column)
sum=0;
for(int j = 0; j < catchers.length; j++){
sum += chart[i][j];
}
System.out.print(sum);
}
//catchers
System.out.print("\nTotal Score Catchers:");
for(int j = 0; j < catchers.length; j++){
System.out.println("");
System.out.print("X"+j+":\t");
//looping over cats (each cat a column)
sum=0;
for(int i = 0; i < cats.length; i++){
sum += chart[i][j];
}
System.out.print(sum);
}
}//print table
public static void main(String[] args){
long t = System.nanoTime();
Controller c = new Controller();
c.playGames();
c.printTable();
System.out.println("");
System.out.println("Time (in ns): "+(System.nanoTime()-t));
}//main
}
package main;
public class Field {
public final int SIZE;
public int[][] field;
public static final int EMPTY = 0;
public static final int CAT = -1;
public static final int BUCKET = 1;
/**
* Constructor
* @param size
*/
Field(int size){
SIZE = size;
field = new int[SIZE][SIZE];
//initialize cat
field[SIZE/2][SIZE/2] = CAT;
}
/**
* Copy/Clone constructor (for cloning existing field)
* @return
*/
Field(Field f){
this(f.SIZE);
//clone the field:
for(int i=0;i<SIZE;i++){
for(int j=0;j<SIZE;j++){
this.field[i][j] = f.field[i][j];
}
}
}
/**
* Accessing the array field[i][j] but allows indices out of range. (Torroidal topology.)
* @param i
* @param j
* @return
*/
public int read(int i, int j){
i = (i%SIZE + SIZE)%SIZE;
j = (j%SIZE + SIZE)%SIZE;
return field[i][j];
}
/**
* Accessing the array field[i][j] but allows indices out of range. (Torroidal topology.)
* @param i
* @param j
* @return
*/
private int write(int i, int j, int value){
i = (i%SIZE + SIZE)%SIZE;
j = (j%SIZE + SIZE)%SIZE;
return field[i][j] = value;
}
/**
* first element is x coordinate, second is y coordinate
* (0,0) is at bottom left, x goes to right, y up
* Allowed steps for the cat:
* y
* [1,1,0]
* [1,C,1]
* [0,1,1]x
* @param move
* @return
*/
public boolean isValidMove(int[] move){
if( (move[1] == 1 && (move[0] == -1 || move[0] == 0)) ||
(move[1] == 0 && (move[0] == -1 || move[0] == 1)) ||
(move[1] ==-1 && (move[0] == 0 || move[0] == 1)) )
{//good so far, check availability of the step.
//find cat:
int pos[] = findCat();
//check neighbours
if(this.read(pos[0]+move[0], pos[1]+move[1]) == EMPTY){
return true; //empty spot
} else {
return false; //bucket already blocking the spot
}
} else {//invalid
return false;
}
}
/**
* Find the position of the cat.
* @return
*/
public int[] findCat(){
int i=0,j=0;
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
if(this.read(i,j) == CAT){
return new int[] {i,j};
}
}
}
System.out.println("Error 404 (Furr-Oh-Furr): Cat not found.");
return new int[] {-1,-1};
}
/**
* Arguments are the coordinates on the grid
* @param pos
* @return
*/
public boolean isValidPosition(int[] pos){
if(this.read(pos[0],pos[1]) == EMPTY){
return true;
} else {
return false;
}
}
public void placeBucket(int[] pos){
this.write(pos[0], pos[1], BUCKET);
}
public void executeMove(int[] move){
int[] pos = findCat();
this.write(pos[0],pos[1],EMPTY);
this.write(pos[0]+move[0],pos[1]+move[1],CAT);
}
public boolean isFinished(){
int[] pos = findCat();
if( this.read(pos[0]-1,pos[1]+1)==BUCKET &&
this.read(pos[0]+0,pos[1]+1)==BUCKET &&
this.read(pos[0]-1,pos[1]+0)==BUCKET &&
this.read(pos[0]+1,pos[1]+0)==BUCKET &&
this.read(pos[0]+0,pos[1]-1)==BUCKET &&
this.read(pos[0]+1,pos[1]-1)==BUCKET)
{
return true;
} else {
return false;
}
}
public String toString(){
String s = "";
for(int j=SIZE-1;j>=0;j--){//lines
s += "|";
for(int i=0;i<SIZE;i++){//columns
if(field[i][j] == EMPTY){
s+=".";
} else if(field[i][j] == BUCKET){
s+="B";
} else {//cat
s+="C";
}
}
s+="|"+j+"\n";
}
return s;
}
}
package players;
/**
* @author randomra
*/
import java.util.Arrays;
import main.Field;
public class FreeCat implements Cat {
final int[][] turns = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 },
{ 0, -1 }, { 1, -1 } };// all valid moves
final int turnCheck = 3;
public String getName() {
return "FreeCat";
}
public int[] takeTurn(Field f) {
int[] pos = f.findCat();
int[] bestMove = { 0, 1 };
int bestMoveCount = -1;
for (int[] t : turns) {
int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
int moveCount = free_count(currPos, turnCheck, f);
if (moveCount > bestMoveCount) {
bestMoveCount = moveCount;
bestMove = t;
}
}
return bestMove;
}
private int free_count(int[] pos, int turnsLeft, Field f) {
if (f.isValidPosition(pos) || Arrays.equals(pos, f.findCat())) {
if (turnsLeft == 0) {
return 1;
}
int routeCount = 0;
for (int[] t : turns) {
int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
int moveCount = free_count(currPos, turnsLeft - 1, f);
routeCount += moveCount;
}
return routeCount;
}
return 0;
}
}
package main;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.*;
public class MyFrame extends JFrame {
private final boolean DISPLAY_COORDINATES = true; // display the coordinates of the cells
public final int width = 640; //size of your window
public final int height = 480;
private static final long serialVersionUID = 1L;
private int size; //number of cells in each direction
private int dx; //number of pixels per cell
private int dy;
private int rad; //radius of cell
private Field field;
private DrawingPanel panel;
public MyFrame (Field f){
this.field = f;
setTitle("Catch The Cat");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
panel = new DrawingPanel();
add(panel);
setSize(width,height);
setVisible(true);
this.size= f.SIZE;
dx = (int) (width / (size*1.2));
dy = (int) (height / (size*1.2));
this.rad = (int) (dx * 0.7f);
}
public void updateField(Field f){
this.field = f;
}
class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public void paint(Graphics g){
//loop throu all cells
for(int iy=-size; iy < size*2; iy++){
for(int ix=-size; ix < size*2; ix++){
switch(field.read(ix,iy)){
case Field.CAT:
g.setColor(Color.BLACK);
break;
case Field.BUCKET:
g.setColor(Color.BLUE);
break;
case Field.EMPTY:
default:
g.setColor(Color.GREEN);
break;
}
// dx*ix + dx*iy/2 for the horizontal shift
// height- dy*dy for flipping coordinate system
g.fillOval( dx*ix+dx*iy/2,height-dy*(iy+2), rad,rad);
if(DISPLAY_COORDINATES){
g.setColor(Color.RED);
g.drawString(ix+", "+iy,dx*ix+dx*iy/2+dx/6,height-dy*(iy+2)+dy/2);
}
}
}
}
}
public static void main (String args[]) {//only for testing
new MyFrame(new Field(10));
}
}
package players;
import main.Field;
public interface Player {
public String getName();
public int[] takeTurn(Field f);
}
package players;
import main.Field;
/**
* Tries to make random moves until it finds a valid one.
* @author user
*
*/
public class RandCat implements Cat{
public String getName(){
return "RandCat";
}
public int[] takeTurn(Field f){
int[][] turns = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};//all valid moves
int[] move;
do {
move = turns[(int) (turns.length * Math.random())];
} while(f.isValidMove(move)==false);
return move;//chose one at random
}
}
package players;
import main.Field;
/**
* Places random Buckets (do not use with big field sizes, very inefficient if field is already pretty full)
* @author user
*
*/
public class RandCatcher implements Catcher {
public String getName(){
return "RandCatcher";
}
public int[] takeTurn(Field f){
int[] pos = {0,0};
do {
pos[0] = (int) (Math.random()*f.SIZE);
pos[1] = (int) (Math.random()*f.SIZE);
} while( f.isValidPosition(pos)==false );
return pos;
}
}
package players;
import main.Field;
/**
* @author CoolGuy
*/
public class SpiralCat implements Cat{
public String getName(){
return "SpiralCat";
}
public int[] takeTurn(Field f){
int[][] turns = {{-1,1},{0,1},{1,0},{1,-1},{0,-1},{-1,0}};//all valid moves
int[] move;
int i = -1;
do {
i++;
move = turns[i];
} while(f.isValidMove(move) == false);
return move;
}
}
package players;
/**
* @author Cool Guy
*/
import main.Field;
public class StraightCat implements Cat{
int lastDirection = -1; //Holds the last direction the cat moved
public String getName(){
return "StraightCat";
}
public int[] takeTurn(Field f){
int[][] turns = {{-1,1},{0,1},{1,0},{1,-1},{0,-1},{-1,0}};//all valid moves
if(lastDirection == -1)
lastDirection = (int) (turns.length * Math.random());
int[] move = turns[lastDirection];
int i = lastDirection;
while(true)
{
if(f.isValidMove(move))
break;
i = (i+1)%6;
lastDirection = i;
move = turns[i];
}
return move;
}
}
package players;
import main.Field;
/**
* Just fills column by column.
* @author user
*
*/
public class StupidFillCatcher implements Catcher {
public String getName(){
return "StupidFillCatcher";
}
public int[] takeTurn(Field f){
for(int i=0; i < f.SIZE; i++){
for(int j=0; j < f.SIZE; j++){
if(f.isValidPosition(new int[] {i,j})){
return new int[] {i,j};
}
}
}
return new int[] {0,0};
}
}
package players;
import main.Field;
/**
* Moves always right. If not possible, moves randomly.
* @author user
*
*/
public class StupidRightCat implements Cat{
public String getName(){
return "StupidRightCat";
}
public int[] takeTurn(Field f){
int[][] turns = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};//all valid moves
int[] move;
if(f.isValidMove(turns[3])){
return turns[3];
} else {
do {
move = turns[(int) (turns.length * Math.random())];
} while(f.isValidMove(move)==false);
return move;//chose one at random
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.