-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
497 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
81
algorithms/src/main/scala/graphs/leejava/colored/Ansi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||
} |
Oops, something went wrong.