Getneightbourhood without edge detection.

This commit is contained in:
Kristian Knarvik 2018-03-07 21:40:06 +01:00
parent ea0a2695cc
commit 29ae17d535
11 changed files with 365 additions and 79 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/bin/ /bin/
.DS_Store .DS_Store
*.xml *.xml
*.iml

View File

@ -4,5 +4,7 @@ IPlayer, INonPlayer -> IActor -> IItem -> Comparable<IItem>
GameEvent<T> -> Event<T> GameEvent<T> -> Event<T>
Game -> Mapreader.readFile()
Game -> createItem()
Game - Rabbit.doTurn(Game) - Game.move() Game - Rabbit.doTurn(Game) - Game.move()
Game.doTurn() - Game.beginTurn() Game.doTurn() - Game.beginTurn()

View File

@ -23,8 +23,7 @@ public class MyGrid<T> implements IGrid<T> {
* new MyGrid(10, 10, ((x, y) -> String.format("(%d,%d)", x, y)); * new MyGrid(10, 10, ((x, y) -> String.format("(%d,%d)", x, y));
* </pre> * </pre>
* *
* @param width * @param area
* @param height
* @param initialiser * @param initialiser
* The initialiser function * The initialiser function
*/ */
@ -43,8 +42,7 @@ public class MyGrid<T> implements IGrid<T> {
/** /**
* Construct a grid with the given dimensions. * Construct a grid with the given dimensions.
* *
* @param width * @param area
* @param height
* @param initElement * @param initElement
* What the cells should initially hold (possibly null) * What the cells should initially hold (possibly null)
*/ */

View File

@ -28,7 +28,7 @@ public class Rabbit implements INonPlayer {
for (IItem item : game.getLocalItems()) { for (IItem item : game.getLocalItems()) {
if (item instanceof Carrot) { if (item instanceof Carrot) {
System.out.println("found carrot!"); System.out.println("found carrot!");
int eaten = item.handleDamage(game, this, 5); int eaten = item.handleDamage(game, this, getDamage());
if (eaten > 0) { if (eaten > 0) {
System.out.println("ate carrot worth " + eaten + "!"); System.out.println("ate carrot worth " + eaten + "!");
food += eaten; food += eaten;
@ -63,7 +63,7 @@ public class Rabbit implements INonPlayer {
@Override @Override
public int getAttack() { public int getAttack() {
return 1000; return 10;
} }
@Override @Override
@ -73,7 +73,7 @@ public class Rabbit implements INonPlayer {
@Override @Override
public int getDamage() { public int getDamage() {
return 1000; return 5;
} }
@Override @Override
@ -106,5 +106,4 @@ public class Rabbit implements INonPlayer {
hp -= amount; hp -= amount;
return amount; return amount;
} }
} }

View File

@ -18,17 +18,13 @@ import inf101.v18.grid.IGrid;
import inf101.v18.grid.ILocation; import inf101.v18.grid.ILocation;
import inf101.v18.rogue101.Main; import inf101.v18.rogue101.Main;
import inf101.v18.rogue101.examples.Carrot; import inf101.v18.rogue101.examples.Carrot;
import inf101.v18.rogue101.items.Manga;
import inf101.v18.rogue101.examples.Rabbit; import inf101.v18.rogue101.examples.Rabbit;
import inf101.v18.rogue101.map.GameMap; import inf101.v18.rogue101.map.GameMap;
import inf101.v18.rogue101.map.IGameMap; import inf101.v18.rogue101.map.IGameMap;
import inf101.v18.rogue101.map.IMapView; import inf101.v18.rogue101.map.IMapView;
import inf101.v18.rogue101.map.MapReader; import inf101.v18.rogue101.map.MapReader;
import inf101.v18.rogue101.objects.Dust; import inf101.v18.rogue101.objects.*;
import inf101.v18.rogue101.objects.IActor;
import inf101.v18.rogue101.objects.IItem;
import inf101.v18.rogue101.objects.INonPlayer;
import inf101.v18.rogue101.objects.IPlayer;
import inf101.v18.rogue101.objects.Wall;
import javafx.scene.canvas.GraphicsContext; import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@ -63,9 +59,7 @@ public class Game implements IGame {
this.painter = painter; this.painter = painter;
this.printer = printer; this.printer = printer;
// TODO: (*very* optional) for advanced factory technique, use addFactory();
// something like "itemFactories.put("R", () -> new Rabbit());"
// must be done *before* you read the map
// NOTE: in a more realistic situation, we will have multiple levels (one map // NOTE: in a more realistic situation, we will have multiple levels (one map
// per level), and (at least for a Roguelike game) the levels should be // per level), and (at least for a Roguelike game) the levels should be
@ -90,8 +84,13 @@ public class Game implements IGame {
} }
public Game(String mapString) { public Game(String mapString) {
printer = new Printer(1280, 720); //printer = new Printer(1280, 720);
painter = new TurtlePainter(1280, 720, null); //painter = new TurtlePainter(1280, 720, null);
printer = null;
painter = null;
addFactory();
IGrid<String> inputGrid = MapReader.readString(mapString); IGrid<String> inputGrid = MapReader.readString(mapString);
this.map = new GameMap(inputGrid.getArea()); this.map = new GameMap(inputGrid.getArea());
for (ILocation loc : inputGrid.locations()) { for (ILocation loc : inputGrid.locations()) {
@ -149,7 +148,7 @@ public class Game implements IGame {
} }
if (random.nextInt(100) < 20) { if (random.nextInt(100) < 20) {
ILocation loc = map.getLocation((int)(Math.random() * map.getWidth()), (int)(Math.random() * map.getHeight())); ILocation loc = map.getLocation(random.nextInt(map.getWidth()), random.nextInt(map.getHeight()));
if (!map.hasActors(loc) && !map.hasItems(loc) && !map.hasWall(loc)) { if (!map.hasActors(loc) && !map.hasItems(loc) && !map.hasWall(loc)) {
map.add(loc, new Carrot()); map.add(loc, new Carrot());
} }
@ -250,20 +249,18 @@ public class Game implements IGame {
return map.canGo(currentLocation, dir); return map.canGo(currentLocation, dir);
} }
private void addFactory() {
itemFactories.put("#", Wall::new);
itemFactories.put("@", Player::new);
itemFactories.put("C", Carrot::new);
itemFactories.put("R", Rabbit::new);
itemFactories.put("M", Manga::new);
itemFactories.put(".", Dust::new);
}
@Override @Override
public IItem createItem(String sym) { public IItem createItem(String sym) {
switch (sym) { switch (sym) {
case "#":
return new Wall();
case ".":
// TODO: add Dust
return null;
case "R":
return new Rabbit();
case "C":
return new Carrot();
case "@":
// TODO: add Player
case " ": case " ":
return null; return null;
default: default:

View File

@ -1,4 +1,4 @@
package inf101.v18.rogue101.examples; package inf101.v18.rogue101.items;
import inf101.v18.gfx.gfxmode.ITurtle; import inf101.v18.gfx.gfxmode.ITurtle;
import inf101.v18.rogue101.game.IGame; import inf101.v18.rogue101.game.IGame;
@ -8,7 +8,7 @@ import javafx.scene.paint.Color;
public class Manga implements IItem { public class Manga implements IItem {
int hp = getMaxHealth(); int hp = getMaxHealth();
@Override /*@Override
public boolean draw(ITurtle painter, double w, double h) { public boolean draw(ITurtle painter, double w, double h) {
painter.save(); painter.save();
painter.jump(-10); painter.jump(-10);
@ -22,7 +22,7 @@ public class Manga implements IItem {
painter.draw(getSize()/2); painter.draw(getSize()/2);
painter.restore(); painter.restore();
return true; return true;
} }*/
@Override @Override
public int getCurrentHealth() { public int getCurrentHealth() {
@ -46,7 +46,7 @@ public class Manga implements IItem {
@Override @Override
public int getSize() { public int getSize() {
return 20; return 5;
} }
@Override @Override

View File

@ -1,13 +1,8 @@
package inf101.v18.rogue101.map; package inf101.v18.rogue101.map;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.org.apache.bcel.internal.generic.ILOAD;
import inf101.v18.gfx.gfxmode.ITurtle; import inf101.v18.gfx.gfxmode.ITurtle;
import inf101.v18.gfx.textmode.Printer; import inf101.v18.gfx.textmode.Printer;
import inf101.v18.grid.GridDirection; import inf101.v18.grid.GridDirection;
@ -16,7 +11,9 @@ import inf101.v18.grid.ILocation;
import inf101.v18.grid.IMultiGrid; import inf101.v18.grid.IMultiGrid;
import inf101.v18.grid.MultiGrid; import inf101.v18.grid.MultiGrid;
import inf101.v18.rogue101.Main; import inf101.v18.rogue101.Main;
import inf101.v18.rogue101.examples.Carrot;
import inf101.v18.rogue101.game.IllegalMoveException; import inf101.v18.rogue101.game.IllegalMoveException;
import inf101.v18.rogue101.items.Manga;
import inf101.v18.rogue101.objects.IActor; import inf101.v18.rogue101.objects.IActor;
import inf101.v18.rogue101.objects.IItem; import inf101.v18.rogue101.objects.IItem;
import inf101.v18.rogue101.objects.Wall; import inf101.v18.rogue101.objects.Wall;
@ -48,6 +45,7 @@ public class GameMap implements IGameMap {
@Override @Override
public void add(ILocation loc, IItem item) { public void add(ILocation loc, IItem item) {
// keep track of location of all items // keep track of location of all items
items.put(item, loc); items.put(item, loc);
// also keep track of whether we need to redraw this cell // also keep track of whether we need to redraw this cell
@ -55,8 +53,26 @@ public class GameMap implements IGameMap {
// do the actual adding // do the actual adding
List<IItem> list = grid.get(loc); List<IItem> list = grid.get(loc);
for (int i = 0; i < list.size(); i++) {
if (item.compareTo(list.get(i)) >= 0) {
list.add(i, item);
return;
}
}
list.add(item); list.add(item);
// TODO: should be sorted! }
public void addRandomItems(ILocation loc) {
if (!this.hasActors(loc) && !this.hasWall(loc)) {
Random random = new Random();
if (random.nextInt(100) < 20) {
this.add(loc, new Carrot());
}
if (random.nextInt(100) < 1) {
this.add(loc, new Manga());
}
}
} }
@Override @Override
@ -243,12 +259,39 @@ public class GameMap implements IGameMap {
@Override @Override
public List<ILocation> getNeighbourhood(ILocation loc, int dist) { public List<ILocation> getNeighbourhood(ILocation loc, int dist) {
if (dist < 0 || loc == null) if (dist < 0 || loc == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
else if (dist == 0) } else if (dist == 0){
return new ArrayList<>(); // empty! return new ArrayList<>(); // empty!
}
// TODO: implement this! //Goes in wider and wider squares, until we have reached dist.
throw new UnsupportedOperationException(); List<ILocation> locations = new ArrayList<>();
for (int i = 1; i <= dist; i++) {
ILocation current = loc;
for (int j = 0; j < i; j++) {
current = current.go(GridDirection.WEST);
current = current.go(GridDirection.NORTH);
}
for (int j = 0; j < i * 2 + 1; j++) {
locations.add(current);
if (j < i * 2) {
current = current.go(GridDirection.EAST);
}
}
for (int j = 0; j < i * 2; j++) {
current = current.go(GridDirection.SOUTH);
locations.add(current);
}
for (int j = 0; j < i * 2; j++) {
current = current.go(GridDirection.WEST);
locations.add(current);
}
for (int j = 0; j < i * 2 - 1; j++) {
current = current.go(GridDirection.NORTH);
locations.add(current);
}
}
return locations;
} }
} }

View File

@ -9,7 +9,7 @@
#. ...R..C. ..R.R..........C.RC....... # #. ...R..C. ..R.R..........C.RC....... #
#..C.....R..... ........RR R..R.....R..# #..C.....R..... ........RR R..R.....R..#
#...R..R.R..............R .R..R........# #...R..R.R..............R .R..R........#
#.R.....R........RRR.......R.. .C....R.# #.R.....R...M....RRR.......R.. .C....R.#
#.C.. ..R. .....R.RC..C....R...R..C. .# #.C.. ..R. .....R.RC..C....R...R..C. .#
#. R..............R R..R........C.....R# #. R..............R R..R........C.....R#
#........############################### #........###############################

View File

@ -1,4 +1,143 @@
package inf101.v18.rogue101.items; package inf101.v18.rogue101.objects;
public class Player { import inf101.v18.grid.GridDirection;
import inf101.v18.rogue101.game.IGame;
import javafx.scene.input.KeyCode;
import java.util.ArrayList;
import java.util.List;
public class Player implements IPlayer {
private int hp = getMaxHealth();
private List<IItem> equipped = new ArrayList<>();
@Override
public void keyPressed(IGame game, KeyCode key) {
if (key == KeyCode.LEFT || key == KeyCode.A) {
tryToMove(game, GridDirection.WEST);
} else if (key == KeyCode.RIGHT || key == KeyCode.D) {
tryToMove(game, GridDirection.EAST);
} else if (key == KeyCode.UP || key == KeyCode.W) {
tryToMove(game, GridDirection.NORTH);
} else if (key == KeyCode.DOWN || key == KeyCode.S) {
tryToMove(game, GridDirection.SOUTH);
} else if (key == KeyCode.E) {
pickUp(game);
} else if (key == KeyCode.Q) {
drop(game);
}
showStatus(game);
}
private void pickUp(IGame game) {
//TODO: If there are several items on a tile, let player choose what to pick up.
if (equipped.size() < 5) {
List<IItem> items = game.getLocalItems();
for (IItem item : items) {
IItem pickedUp = game.pickUp(item);
if (pickedUp != null) {
equipped.add(pickedUp);
game.displayMessage("Picked up " + pickedUp.getName());
return;
}
}
game.displayMessage("There is nothing to pick up.");
} else {
game.displayMessage("Your inventory is full.");
}
}
private void pickUpV2(IGame game) {
List<IItem> items = game.getLocalItems();
if (items.size() < 1) {
game.displayMessage("There is nothing to pick up.");
return;
}
StringBuilder msg = new StringBuilder("Items on this tile:");
for (int i = 0; i < items.size(); i++) {
msg.append(" [").append(i).append("] ").append(items.get(i).getName());
}
game.displayMessage(msg.toString());
if (equipped.size() < 5) {
//TODO: Let user choose 1-5.
} else {
game.displayMessage("Your inventory is full.");
}
}
private void drop(IGame game) {
//TODO: Find a way to implement V2.
if (!equipped.isEmpty()) {
if (game.drop(equipped.get(0))) {
equipped.remove(0);
game.displayMessage("Item dropped.");
} else {
game.displayMessage("The ground rejected the item.");
}
} else {
game.displayMessage("You have nothing to drop.");
}
}
private void showStatus(IGame game) {
List<String> items = new ArrayList<>();
for (IItem item : equipped) {
String name = item.getName();
items.add(Character.toUpperCase(name.charAt(0)) + name.substring(1));
}
game.formatStatus("HP: %d/%d ATK: %d DEF: %s INV: %s", hp, getMaxHealth(), getAttack(), getDefence(), String.join(",", items));
}
private void tryToMove(IGame game, GridDirection dir) {
if (game.canGo(dir)) {
game.move(dir);
} else {
game.displayMessage("Umm, it is not possible to move in that direction.");
}
}
@Override
public int getAttack() {
return 10;
}
@Override
public int getDamage() {
return 10;
}
@Override
public int getCurrentHealth() {
return hp;
}
@Override
public int getDefence() {
return 1;
}
@Override
public int getMaxHealth() {
return 100;
}
@Override
public String getName() {
return "Person";
}
@Override
public int getSize() {
return 10;
}
@Override
public String getSymbol() {
return "X";
}
@Override
public int handleDamage(IGame game, IItem source, int amount) {
hp -= amount;
return amount;
}
} }

View File

@ -2,19 +2,50 @@ package inf101.v18.rogue101.tests;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import inf101.v18.rogue101.objects.IItem;
import org.junit.Test; import org.junit.Test;
import inf101.v18.grid.ILocation; import inf101.v18.grid.ILocation;
import inf101.v18.rogue101.map.GameMap; import inf101.v18.rogue101.map.GameMap;
class GameMapTest { import java.util.List;
public class GameMapTest {
@Test @Test
void testSortedAdd() { public void testSortedAdd() {
GameMap gameMap = new GameMap(20, 20); GameMap gameMap = new GameMap(20, 20);
ILocation location = gameMap.getLocation(10, 10); ILocation location = gameMap.getLocation(10, 10);
// TODO: for (int i = 0; i < 30; i++) {
fail("Not yet implemented"); gameMap.addRandomItems(location);
}
List<IItem> items = gameMap.getAll(location);
for (int i = 0; i < items.size() - 1; i++) {
assertTrue(items.get(i).compareTo(items.get(i + 1)) >= 0);
}
} }
@Test
public void testGetNeighbours() {
GameMap gameMap = new GameMap(20, 20);
ILocation location = gameMap.getLocation(0, 0);
List<ILocation> neighbours = gameMap.getNeighbourhood(location, 1);
for (ILocation neighbour : neighbours) {
assertTrue(location.gridDistanceTo(neighbour) <= 1);
}
assertEquals(8, neighbours.size());
neighbours = gameMap.getNeighbourhood(location, 2);
for (ILocation neighbour : neighbours) {
assertTrue(location.gridDistanceTo(neighbour) <= 2);
}
assertEquals(24, neighbours.size());
neighbours = gameMap.getNeighbourhood(location, 3);
for (ILocation neighbour : neighbours) {
assertTrue(location.gridDistanceTo(neighbour) <= 3);
}
assertEquals(48, neighbours.size());
}
} }

View File

@ -7,36 +7,112 @@ import org.junit.Test;
import inf101.v18.grid.GridDirection; import inf101.v18.grid.GridDirection;
import inf101.v18.grid.ILocation; import inf101.v18.grid.ILocation;
import inf101.v18.rogue101.game.Game; import inf101.v18.rogue101.game.Game;
import inf101.v18.rogue101.game.IGame;
import inf101.v18.rogue101.map.GameMap;
import inf101.v18.rogue101.objects.IItem;
import inf101.v18.rogue101.objects.IPlayer; import inf101.v18.rogue101.objects.IPlayer;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
class PlayerTest { public class PlayerTest {
public static String TEST_MAP = "40 5\n" // //Tiny maps in collaboration with Stian J. Husum
+ "########################################\n" // private static String NO_WALLS_MAP = "1 1\n"
+ "#...... ..C.R ......R.R......... ..R...#\n" // + "@\n";
+ "#.R@R...... ..........RC..R...... ... .#\n" //
+ "#... ..R........R......R. R........R.RR#\n" // private static String EMPTY_MAP = "5 5\n"
+ "########################################\n" // + "#####\n"
; + "# #\n"
+ "# @ #\n"
+ "# #\n"
+ "#####\n";
private static String RABBIT_MAP = "5 5\n"
+ "#####\n"
+ "#RRR#\n"
+ "#R@R#\n"
+ "#RRR#\n"
+ "#####\n";
private static String CARROT_MAP = "5 5\n"
+ "#####\n"
+ "#CCC#\n"
+ "#C@C#\n"
+ "#CCC#\n"
+ "#####\n";
@Test @Test
void testPlayer1() { public void testOutOfBounds() {
// new game with our test map Game game = new Game(NO_WALLS_MAP);
Game game = new Game(TEST_MAP); IPlayer player = (IPlayer) game.setCurrent(0, 0);
// pick (3,2) as the "current" position; this is where the player is on the
// test map, so it'll set up the player and return it
IPlayer player = (IPlayer) game.setCurrent(3, 2);
// find players location
ILocation loc = game.getLocation(); ILocation loc = game.getLocation();
// press "UP" key player.keyPressed(game, KeyCode.LEFT);
player.keyPressed(game, KeyCode.UP); assertEquals(loc, game.getLocation());
// see that we moved north
assertEquals(loc.go(GridDirection.NORTH), game.getLocation());
} }
@Test
public void testActor() {
Game game = new Game(RABBIT_MAP);
IPlayer player = (IPlayer) game.setCurrent(2, 2);
ILocation loc = game.getLocation();
player.keyPressed(game, KeyCode.LEFT);
assertEquals(loc, game.getLocation());
player.keyPressed(game, KeyCode.RIGHT);
assertEquals(loc, game.getLocation());
player.keyPressed(game, KeyCode.UP);
assertEquals(loc, game.getLocation());
player.keyPressed(game, KeyCode.DOWN);
assertEquals(loc, game.getLocation());
}
@Test
public void testItem() {
Game game = new Game(CARROT_MAP);
IPlayer player = (IPlayer) game.setCurrent(2, 2);
ILocation loc = game.getLocation();
player.keyPressed(game, KeyCode.RIGHT);
assertEquals(loc.go(GridDirection.EAST), game.getLocation());
game.doTurn();
player.keyPressed(game, KeyCode.LEFT);
game.doTurn();
player.keyPressed(game, KeyCode.LEFT);
assertEquals(loc.go(GridDirection.WEST), game.getLocation());
game.doTurn();
player.keyPressed(game, KeyCode.UP);
game.doTurn();
player.keyPressed(game, KeyCode.RIGHT);
assertEquals(loc.go(GridDirection.NORTH), game.getLocation());
game.doTurn();
player.keyPressed(game, KeyCode.DOWN);
game.doTurn();
player.keyPressed(game, KeyCode.DOWN);
assertEquals(loc.go(GridDirection.SOUTH), game.getLocation());
}
@Test
public void testWallsAndKeys() {
Game game = new Game(EMPTY_MAP);
IPlayer player = (IPlayer) game.setCurrent(2, 2);
ILocation loc = game.getLocation();
player.keyPressed(game, KeyCode.UP);
game.doTurn();
player.keyPressed(game, KeyCode.UP);
game.doTurn();
assertEquals(loc.go(GridDirection.NORTH), game.getLocation());
player.keyPressed(game, KeyCode.DOWN);
game.doTurn();
player.keyPressed(game, KeyCode.RIGHT);
game.doTurn();
player.keyPressed(game, KeyCode.RIGHT);
game.doTurn();
assertEquals(loc.go(GridDirection.EAST), game.getLocation());
player.keyPressed(game, KeyCode.LEFT);
game.doTurn();
player.keyPressed(game, KeyCode.DOWN);
game.doTurn();
player.keyPressed(game, KeyCode.DOWN);
game.doTurn();
assertEquals(loc.go(GridDirection.SOUTH), game.getLocation());
player.keyPressed(game, KeyCode.UP);
game.doTurn();
player.keyPressed(game, KeyCode.LEFT);
game.doTurn();
player.keyPressed(game, KeyCode.LEFT);
assertEquals(loc.go(GridDirection.WEST), game.getLocation());
}
} }