Skip to content

Commit

Permalink
lee java
Browse files Browse the repository at this point in the history
  • Loading branch information
djnzx committed Jan 11, 2024
1 parent da1294b commit fbb6772
Show file tree
Hide file tree
Showing 6 changed files with 497 additions and 0 deletions.
159 changes: 159 additions & 0 deletions algorithms/src/main/scala/graphs/leejava/Lee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package graphs.leejava;

import graphs.leejava.colored.Ansi;
import graphs.leejava.colored.Attribute;
import graphs.leejava.colored.Colored;

import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class Lee {
private static final int EMPTY = 0;
private static final int START = 1;
private static final int OBSTACLE = -10;
private final int width;
private final int height;
private final int[][] board;

public Lee(int width, int height) {
this.width = width;
this.height = height;
this.board = new int[height][width];
}

private int get(int x, int y) {
return board[y][x];
}

private void set(int x, int y, int value) {
board[y][x] = value;
}

private int get(Point p) {
return get(p.x, p.y);
}

private void set(Point p, int value) {
set(p.x, p.y, value);
}

private boolean isOnBoard(Point p) {
return p.x >= 0 && p.x < width && p.y >= 0 && p.y < height;
}

private boolean isUnvisited(Point p) {
return get(p) == EMPTY;
}

// offsets, not points
private Supplier<Stream<Point>> deltas() {
return () -> Stream.of(
Point.of(-1, 0),
Point.of(0, -1),
Point.of(1, 0),
Point.of(0, 1)
);
}

private Stream<Point> neighbours(Point p) {
return deltas().get()
.map(d -> p.move(d.x, d.y))
.filter(this::isOnBoard);
}

private Stream<Point> neighboursUnvisited(Point p) {
return neighbours(p)
.filter(this::isUnvisited);
}

private Stream<Point> neighboursByValue(Point pt, int value) {
return neighbours(pt)
.filter(p -> get(p) == value);
}

private void initializeBoard(Set<Point> obstacles) {
obstacles.forEach(p -> set(p, OBSTACLE));
}

public Optional<Iterable<Point>> trace(Point src, Point dst, Set<Point> obstacles) {
// 1. initialization
initializeBoard(obstacles);
System.out.println("2a");
// 2. fill the board
int[] counter = {START};
set(src, counter[0]);
counter[0]++;
boolean found = false;
for (Set<Point> curr = Set.of(src); !(found || curr.isEmpty()); counter[0]++) {
System.out.println(curr.size());
System.out.println(boardFormatted(List.of()));
Set<Point> next = curr.stream()
.flatMap(this::neighboursUnvisited)
.collect(Collectors.toSet());
next.forEach(p -> set(p, counter[0]));
found = next.contains(dst);
curr = next;
}
System.out.println("2b");
// 3. backtrack (reconstruct path)
if (!found) return Optional.empty();
LinkedList<Point> path = new LinkedList<>();
path.add(dst);
counter[0]--;
Point curr = dst;
while (counter[0] > START) {
counter[0]--;
Point prev = neighboursByValue(curr, counter[0])
.findFirst()
// .reduce((p1, p2) -> p2)
.orElseThrow(() -> new RuntimeException("impossible"));
path.addFirst(prev);
curr = prev;
}
return Optional.of(path);
}

private String cellFormatted(Point p, Set<Point> path) {
int value = get(p);
String valueF = String.format("%3d", value);

if (value == OBSTACLE) {
Attribute a = new Attribute(Ansi.ColorFont.BLUE);
return Colored.build(" XX", a);
}

if (path.isEmpty()) return valueF;

if (path.contains(p)) {
Attribute a = new Attribute(Ansi.ColorFont.RED);
return Colored.build(valueF, a);
}

return valueF;
}

public String boardFormatted(Iterable<Point> path0) {
Set<Point> path = StreamSupport
.stream(path0.spliterator(), false)
.collect(Collectors.toSet());
return IntStream.range(0, height).mapToObj(y ->
IntStream.range(0, width)
.mapToObj(x -> Point.of(x, y))
.map(p -> cellFormatted(p, path))
.collect(Collectors.joining())
).collect(Collectors.joining("\n"));
}

@Override
public String toString() {
return boardFormatted(Set.of());
}

}
44 changes: 44 additions & 0 deletions algorithms/src/main/scala/graphs/leejava/LeeApp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package graphs.leejava;

import java.util.Optional;
import java.util.Set;

public class LeeApp {

public static void main(String[] args) {
Lee lee = new Lee(20, 15);
Point src = Point.of(0, 0);
Point dst =
// Point.of(19, 14);
Point.of(19, 0);
Set<Point> obstacles = Set.of(
Point.of(5,14),
Point.of(5,13),
Point.of(5,12),
Point.of(5,11),
Point.of(5,10),
Point.of(5,9),
Point.of(5,8),

Point.of(10,0),
Point.of(10,1),
Point.of(10,2),
Point.of(10,3),
Point.of(10,4),
Point.of(10,5),
Point.of(10,6),
Point.of(10,7),
Point.of(10,8)
);

System.out.println(1);
Optional<Iterable<Point>> trace = lee.trace(src, dst, obstacles);
System.out.println(2);
System.out.println(trace);
System.out.println();
System.out.println(lee);
System.out.println();
trace.ifPresent(path -> System.out.println(lee.boardFormatted(path)));
}

}
37 changes: 37 additions & 0 deletions algorithms/src/main/scala/graphs/leejava/Point.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package graphs.leejava;

public class Point {
public final int x;
public final int y;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}

@Override
public int hashCode() {
return x << 16 + y;
}

public Point(int x, int y) {
this.x = x;
this.y = y;
}

public static Point of(int x, int y) {
return new Point(x, y);
}

@Override
public String toString() {
return String.format("[%d,%d]", x, y);
}

public Point move(int dx, int dy) {
return new Point(x + dx, y + dy);
}
}
81 changes: 81 additions & 0 deletions algorithms/src/main/scala/graphs/leejava/colored/Ansi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package graphs.leejava.colored;

/**
* @author alexr
* @version 0.1
* @see <a href="http://ascii-table.com/ansi-escape-sequences.php">Ansi escape
* codes</a>
*/
public class Ansi {

//public static final String PREFIX = "\033[";
public static final String PREFIX = "\u001B[";
public static final String SEPARATOR = ";";
public static final String POSTFIX = "m";
public static final String RESET = PREFIX + "0" + POSTFIX;

public enum ColorFont {
BLACK("30"),
RED("31"),
GREEN("32"),
YELLOW("33"),
BLUE("34"),
MAGENTA("35"),
CYAN("36"),
WHITE("37"),
NONE("");

private final String _code;

ColorFont(String code) {
_code = code;
}

public String code() {
return _code;
}
}

public enum ColorBack {
BLACK("40"),
RED("41"),
GREEN("42"),
YELLOW("43"),
BLUE("44"),
MAGENTA("45"),
CYAN("46"),
WHITE("47"),
NONE("");

private final String _code;

ColorBack(String code) {
_code = code;
}

public String code() {
return _code;
}
}

public enum Style {
CLEAR("0"),
BOLD("1"),
LIGHT("1"),
DARK("2"),
UNDERLINE("4"),
REVERSE("7"),
HIDDEN("8"),
NONE("");

private final String _code; // Ansi escape code

Style(String code) {
_code = code;
}

public String code() {
return _code;
}
}
}
Loading

0 comments on commit fbb6772

Please sign in to comment.