Skip to content

Commit

Permalink
Add Tanks game
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalibo committed Dec 1, 2017
1 parent ce39c05 commit f8dd8f0
Show file tree
Hide file tree
Showing 8 changed files with 480 additions and 3 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ launch game

![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/sR35V1.gif) ![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/IFREtC.gif) ![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/bUdlw7.gif) ![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/x82Vbe.gif)

![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/AwX9jY.gif)
![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/AwX9jY.gif) ![](https://raw.githubusercontent.com/vitalibo/Brick-Game-9999-in-1/assets/docs/img/ar3crF.gif)

- Board panel `capacity [20x10]`
- Preview panel `capacity [4x4]`
Expand All @@ -43,4 +43,5 @@ launch game
- `0001` Snake
- `0002` Race
- `0003` Tetris
- `0004` Shoot
- `0004` Shoot
- `0005` Tanks
4 changes: 3 additions & 1 deletion src/main/java/com/github/vitalibo/brickgame/Run.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.github.vitalibo.brickgame.game.race.RaceGame;
import com.github.vitalibo.brickgame.game.shoot.ShootGame;
import com.github.vitalibo.brickgame.game.snake.SnakeGame;
import com.github.vitalibo.brickgame.game.tanks.TanksGame;
import com.github.vitalibo.brickgame.game.tetris.TetrisGame;

public class Run {
Expand All @@ -19,7 +20,8 @@ public class Run {
SnakeGame.class,
RaceGame.class,
TetrisGame.class,
ShootGame.class
ShootGame.class,
TanksGame.class
};
Menu.setGames(GAMES);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.github.vitalibo.brickgame.game.tanks;

import com.github.vitalibo.brickgame.game.Point;
import com.github.vitalibo.brickgame.game.Shape;
import com.github.vitalibo.brickgame.util.Random;
import lombok.Getter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

class Battlefield {

private static final Shape TANK_SHADOW = Shape.of(3, 0x7, 0x7, 0x7);

@Getter
private final List<Tank> tanks = new ArrayList<>();

public int canDoUp(Tank tank) {
return testDoStep(tank, Tank::doUp, Direction.DOWN);
}

public int canDoRight(Tank tank) {
return testDoStep(tank, Tank::doRight, Direction.LEFT);
}

public int canDoDown(Tank tank) {
return testDoStep(tank, Tank::doDown, Direction.UP);
}

public int canDoLeft(Tank tank) {
return testDoStep(tank, Tank::doLeft, Direction.RIGHT);
}

private int testDoStep(Tank tank, Consumer<Tank> step, Direction direction) {
Tank clone = new Tank(tank);
step.accept(clone);

if (clone.verify()) {
return 0;
}

if (!hasOverlap(clone)) {
return 1;
}

if (tank.getDirection() != direction) {
return 0;
}

step.accept(clone);
if (clone.verify() || hasOverlap(clone)) {
return 0;
}

return 2;
}


private boolean hasOverlap(Tank tank) {
return tanks.stream()
.filter(o -> !o.equals(tank))
.flatMap(Tank::stream)
.anyMatch(tank::contains);
}

public void spawn() {
spawn(4);
}

private void spawn(int attempt) {
if (attempt == 0) {
return;
}

Tank tank = Spawn.randomEnemyTanks();
boolean hasOverlap = tanks.stream()
.filter(o -> !o.equals(tank))
.flatMap(o -> TANK_SHADOW.apply(o.getPoint()))
.anyMatch(tank::contains);

if (hasOverlap) {
spawn(attempt - 1);
return;
}

tanks.add(tank);
}

static class Spawn {

private static final List<Point> SPAWN_POINTS =
Arrays.asList(
Point.of(0, 0), Point.of(0, 7),
Point.of(17, 0), Point.of(17, 7));

public static Tank myTank() {
return point(Point.of(9, 4));
}

public static List<Tank> enemyTanks() {
return SPAWN_POINTS.stream().map(Battlefield.Spawn::point)
.collect(Collectors.toList());
}

private static Tank randomEnemyTanks() {
return point(SPAWN_POINTS.get(
Random.nextInt(SPAWN_POINTS.size())));
}

private static Tank point(Point point) {
return new Tank(Point.of(point), Direction.random());
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.github.vitalibo.brickgame.game.tanks;

import com.github.vitalibo.brickgame.game.Point;
import com.github.vitalibo.brickgame.util.Random;
import lombok.AllArgsConstructor;
import lombok.experimental.Delegate;

import java.util.function.Consumer;

@AllArgsConstructor
enum Direction implements Consumer<Point> {

UP(Point::doUp), RIGHT(Point::doRight),
DOWN(Point::doDown), LEFT(Point::doLeft);

@Delegate
private final Consumer<Point> consumer;

public static Direction random() {
return values()[Random.nextInt(4)];
}

}
25 changes: 25 additions & 0 deletions src/main/java/com/github/vitalibo/brickgame/game/tanks/Shot.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.github.vitalibo.brickgame.game.tanks;

import com.github.vitalibo.brickgame.game.Point;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
class Shot implements Runnable {

@Getter
private final Point point;
@Getter
private final Direction direction;

@Override
public void run() {
direction.accept(point);
}

public boolean verify() {
return (point.getX() < 0 || point.getX() > 9)
|| (point.getY() < 0 || point.getY() > 19);
}

}
101 changes: 101 additions & 0 deletions src/main/java/com/github/vitalibo/brickgame/game/tanks/Tank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package com.github.vitalibo.brickgame.game.tanks;

import com.github.vitalibo.brickgame.game.Point;
import com.github.vitalibo.brickgame.game.Shape;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Delegate;

import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@EqualsAndHashCode(of = "uuid")
class Tank implements List<Point> {

private static final Shape[] STATES = new Shape[]
{
Shape.of(3, 0x2, 0x7, 0x5),
Shape.of(3, 0x6, 0x3, 0x6),
Shape.of(3, 0x5, 0x7, 0x2),
Shape.of(3, 0x3, 0x6, 0x3)
};

private final UUID uuid;

@Getter
private Point point;
@Getter
private Direction direction;
@Delegate
private List<Point> points;

Tank(Tank o) {
this(o.uuid, Point.of(o.point), o.direction);
}

Tank(Point point, Direction direction) {
this(UUID.randomUUID(), point, direction);
}

Tank(UUID uuid, Point point, Direction direction) {
this.uuid = uuid;
this.point = point;
this.direction = direction;
this.points = state(point, direction.ordinal());
}

public void doDown() {
doStep(Direction.DOWN);
}

public void doLeft() {
doStep(Direction.LEFT);
}

public void doRight() {
doStep(Direction.RIGHT);
}

public void doUp() {
doStep(Direction.UP);
}

private void doStep(Direction dr) {
if (dr == this.direction) {
points.forEach(dr);
dr.accept(point);
return;
}

points = state(point, dr.ordinal());
this.direction = dr;
}

public boolean verify() {
return (point.getX() < 0 || point.getX() > 7)
|| (point.getY() < 0 || point.getY() > 17);
}

public Shot doShot() {
return new Shot(
Point.of(
point.getY() + 1 + shifting(direction, Direction.UP, Direction.DOWN),
point.getX() + 1 + shifting(direction, Direction.LEFT, Direction.RIGHT)),
direction);
}

public boolean hasKilled(Shot shot) {
return points.contains(shot.getPoint());
}

private static List<Point> state(Point point, int state) {
return STATES[state].apply(point)
.collect(Collectors.toList());
}

private static int shifting(Direction dr, Direction lower, Direction upper) {
return dr == lower ? -1 : dr == upper ? 1 : 0;
}

}
Loading

0 comments on commit f8dd8f0

Please sign in to comment.