diff --git a/client/src/main/java/ru/trader/controllers/RoutersController.java b/client/src/main/java/ru/trader/controllers/RoutersController.java index 6c37f40..96dcd68 100644 --- a/client/src/main/java/ru/trader/controllers/RoutersController.java +++ b/client/src/main/java/ru/trader/controllers/RoutersController.java @@ -3,12 +3,10 @@ package ru.trader.controllers; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; -import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.TableView; -import ru.trader.core.Vendor; import ru.trader.model.MarketModel; import ru.trader.model.OfferDescModel; import ru.trader.model.OrderModel; @@ -16,9 +14,7 @@ import ru.trader.model.VendorModel; import ru.trader.view.support.NumberField; -import java.awt.*; import java.util.Collection; -import java.util.stream.Collectors; public class RoutersController { diff --git a/client/src/main/java/ru/trader/model/MarketModel.java b/client/src/main/java/ru/trader/model/MarketModel.java index 2e384e9..c380f98 100644 --- a/client/src/main/java/ru/trader/model/MarketModel.java +++ b/client/src/main/java/ru/trader/model/MarketModel.java @@ -19,6 +19,7 @@ public class MarketModel { private final static Logger LOG = LoggerFactory.getLogger(MarketModel.class); private final Market market; + private final MarketAnalyzer analyzer; private final Collection listener = new ArrayList<>(); @@ -41,6 +42,7 @@ public class MarketModel { public MarketModel(Market market) { this.market = market; + analyzer = new MarketAnalyzer(market); items = new SimpleListProperty(BindingsHelper.observableList(market.getItems(), this::getItemDesc)); vendors = new SimpleListProperty(BindingsHelper.observableList(market.get(), this::asModel)); } @@ -168,7 +170,7 @@ public class MarketModel { } public ObservableList getTop(int limit, double balance, long max){ - return BindingsHelper.observableList(market.getTop(limit, balance, max), (o) -> { + return BindingsHelper.observableList(analyzer.getTop(limit, balance, max), (o) -> { OrderModel model = new OrderModel(asOfferDescModel(o.getSell()), balance, max); model.setBuyer(asModel(o.getBuy())); model.setCount(model.getMax()); diff --git a/core/src/main/java/ru/trader/core/Market.java b/core/src/main/java/ru/trader/core/Market.java index fab2fbb..5993d71 100644 --- a/core/src/main/java/ru/trader/core/Market.java +++ b/core/src/main/java/ru/trader/core/Market.java @@ -42,8 +42,6 @@ public interface Market { void setChange(boolean change); - Collection getTop(int limit, double balance, long max); - void updateName(Vendor vendor, String name); void updateName(Item item, String name); diff --git a/core/src/main/java/ru/trader/core/MarketAnalyzer.java b/core/src/main/java/ru/trader/core/MarketAnalyzer.java new file mode 100644 index 0000000..4fa3f3e --- /dev/null +++ b/core/src/main/java/ru/trader/core/MarketAnalyzer.java @@ -0,0 +1,87 @@ +package ru.trader.core; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.trader.graph.Graph; +import ru.trader.graph.Path; +import ru.trader.graph.PathRoute; + +import java.util.Collection; +import java.util.Iterator; +import java.util.TreeSet; + +public class MarketAnalyzer { + private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzer.class); + + private Market market; + private Graph graph; + private double stock; + private double maxDistance; + private int jumps; + + + public MarketAnalyzer(Market market) { + this.market = market; + } + + public Collection getTop(int limit, double balance, long max){ + LOG.debug("Get top {}", limit); + TreeSet top = new TreeSet<>(); + for (Vendor vendor : market.get()) { + LOG.trace("Check vendor {}", vendor); + for (Offer sell : vendor.getAllSellOffers()) { + long count = Math.min(max, (long) Math.floor(balance / sell.getPrice())); + LOG.trace("Sell offer {}, count = {}", sell, count); + if (count == 0) continue; + Iterator buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator(); + while (buyers.hasNext()){ + Offer buy = buyers.next(); + Order order = new Order(sell, buy, count); + LOG.trace("Buy offer {} profit = {}", buy, order.getProfit()); + if (order.getProfit() <= 0 ) break; + if (top.size() == limit){ + LOG.trace("Min order {}", top.first()); + if (top.first().getProfit() < order.getProfit()) { + LOG.trace("Add to top"); + top.add(order); + top.pollFirst(); + } else { + LOG.trace("Is low profit, skip"); + break; + } + } else { + top.add(order); + } + } + } + } + return top; + } + + private void rebuild(Vendor source){ + graph = new Graph<>(source, market.get(), stock, maxDistance, true, jumps, PathRoute::new); + } + + private void setSource(Vendor source){ + if (graph == null || !graph.getRoot().equals(source)) + rebuild(source); + } + + public Collection> getPaths(Vendor from, Vendor to){ + setSource(from); + return graph.getPathsTo(to, true); + } + + + public void setStock(double stock) { + this.stock = stock; + } + + public void setMaxDistance(double maxDistance) { + this.maxDistance = maxDistance; + } + + public void setJumps(int jumps) { + this.jumps = jumps; + } +} diff --git a/core/src/main/java/ru/trader/core/MarketSupport.java b/core/src/main/java/ru/trader/core/MarketSupport.java index 7ff323f..0d557e2 100644 --- a/core/src/main/java/ru/trader/core/MarketSupport.java +++ b/core/src/main/java/ru/trader/core/MarketSupport.java @@ -169,39 +169,5 @@ public abstract class MarketSupport implements Market { this.change = change; } - @Override - public Collection getTop(int limit, double balance, long max){ - LOG.debug("Get top {}", limit); - TreeSet top = new TreeSet<>(); - for (Vendor vendor : getVendors()) { - LOG.trace("Check vendor {}", vendor); - for (Offer sell : vendor.getAllSellOffers()) { - long count = Math.min(max, (long) Math.floor(balance / sell.getPrice())); - LOG.trace("Sell offer {}, count = {}", sell, count); - if (count == 0) continue; - Iterator buyers = getStatBuy(sell.getItem()).getOffers().descendingIterator(); - while (buyers.hasNext()){ - Offer buy = buyers.next(); - Order order = new Order(sell, buy, count); - LOG.trace("Buy offer {} profit = {}", buy, order.getProfit()); - if (order.getProfit() <= 0 ) break; - if (top.size() == limit){ - LOG.trace("Min order {}", top.first()); - if (top.first().getProfit() < order.getProfit()) { - LOG.trace("Add to top"); - top.add(order); - top.pollFirst(); - } else { - LOG.trace("Is low profit, skip"); - break; - } - } else { - top.add(order); - } - } - } - } - return top; - } } diff --git a/core/src/main/java/ru/trader/core/Order.java b/core/src/main/java/ru/trader/core/Order.java index 3090cb2..d91054f 100644 --- a/core/src/main/java/ru/trader/core/Order.java +++ b/core/src/main/java/ru/trader/core/Order.java @@ -8,10 +8,18 @@ public class Order implements Comparable { private Offer sell; private Offer buy; private double profit; + private long count; + + public Order(Offer sell, Offer buy) { + this.sell = sell; + this.buy = buy; + this.profit = Double.NaN; + } public Order(Offer sell, Offer buy, long count) { this.sell = sell; this.buy = buy; + this.count = count; this.profit = (buy.getPrice() - sell.getPrice()) * count; } @@ -23,10 +31,31 @@ public class Order implements Comparable { return buy; } + public void setCount(long count){ + this.count = count; + this.profit = (buy.getPrice() - sell.getPrice()) * count; + } + public double getProfit(){ return profit; } + public Order getCopy(long count){ + return new Order(sell, buy, count); + } + + public long getCount() { + return count; + } + + public double getDistance() { + return sell.getVendor().getDistance(buy.getVendor()); + } + + public boolean isBuyer(Vendor buyer) { + return buy.getVendor().equals(buyer); + } + @Override public int compareTo(@NotNull Order order) { Objects.requireNonNull(order, "Not compare with null"); @@ -56,11 +85,8 @@ public class Order implements Comparable { @Override public int hashCode() { int result; - long temp; result = sell.hashCode(); result = 31 * result + buy.hashCode(); - temp = Double.doubleToLongBits(profit); - result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } @@ -73,4 +99,5 @@ public class Order implements Comparable { sb.append('}'); return sb.toString(); } + } diff --git a/core/src/main/java/ru/trader/core/Route.java b/core/src/main/java/ru/trader/core/Route.java new file mode 100644 index 0000000..50e450c --- /dev/null +++ b/core/src/main/java/ru/trader/core/Route.java @@ -0,0 +1,25 @@ +package ru.trader.core; + +import ru.trader.graph.Path; + +import java.util.LinkedList; + +public class Route { + private double profit; + private double distance; + private final LinkedList orders = new LinkedList<>(); + + public Route() { + profit = 0; + distance = 0; + } + + public void add(Order order){ + orders.add(order); + profit += order.getProfit(); + distance += order.getDistance(); + } + + + +} diff --git a/core/src/main/java/ru/trader/core/Ship.java b/core/src/main/java/ru/trader/core/Ship.java new file mode 100644 index 0000000..70feb01 --- /dev/null +++ b/core/src/main/java/ru/trader/core/Ship.java @@ -0,0 +1,52 @@ +package ru.trader.core; + +public class Ship { + + private double balance; + private long cargo; + private double engine; + private int jumps; + + public Ship(double balance, long cargo, double engine, int jumps) { + this.balance = balance; + this.cargo = cargo; + this.engine = engine; + this.jumps = jumps; + } + + public static Ship copyOf(Ship other){ + return new Ship(other.balance, other.cargo, other.engine, other.jumps); + } + + public double getBalance() { + return balance; + } + + public void setBalance(double balance) { + this.balance = balance; + } + + public long getCargo() { + return cargo; + } + + public void setCargo(long cargo) { + this.cargo = cargo; + } + + public double getEngine() { + return engine; + } + + public void setEngine(double engine) { + this.engine = engine; + } + + public int getJumps() { + return jumps; + } + + public void setJumps(int jumps) { + this.jumps = jumps; + } +} diff --git a/core/src/main/java/ru/trader/core/Vendor.java b/core/src/main/java/ru/trader/core/Vendor.java index 9c70fa4..5dbf858 100644 --- a/core/src/main/java/ru/trader/core/Vendor.java +++ b/core/src/main/java/ru/trader/core/Vendor.java @@ -3,6 +3,7 @@ package ru.trader.core; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ru.trader.graph.Connectable; import java.util.Collection; import java.util.Collections; @@ -10,7 +11,7 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -public abstract class Vendor implements Comparable { +public abstract class Vendor implements Comparable, Connectable { private final static Logger LOG = LoggerFactory.getLogger(Vendor.class); private String name; @@ -111,10 +112,16 @@ public abstract class Vendor implements Comparable { return name != null ? other.name != null ? name.compareTo(other.name) : -1 : 0; } + @Override public double getDistance(Vendor other){ return getDistance(other.x, other.y, other.z); } + @Override + public boolean canRefill() { + return !getAllSellOffers().isEmpty() || !getAllBuyOffers().isEmpty(); + } + public double getDistance(double x, double y, double z){ return Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y-this.y, 2) + Math.pow(z - this.z, 2)); } diff --git a/core/src/main/java/ru/trader/graph/Connectable.java b/core/src/main/java/ru/trader/graph/Connectable.java new file mode 100644 index 0000000..757f2ec --- /dev/null +++ b/core/src/main/java/ru/trader/graph/Connectable.java @@ -0,0 +1,9 @@ +package ru.trader.graph; + +public interface Connectable { + + public double getDistance(T other); + + public boolean canRefill(); + +} diff --git a/core/src/main/java/ru/trader/graph/Edge.java b/core/src/main/java/ru/trader/graph/Edge.java new file mode 100644 index 0000000..24f12f9 --- /dev/null +++ b/core/src/main/java/ru/trader/graph/Edge.java @@ -0,0 +1,60 @@ +package ru.trader.graph; + +public class Edge> { + protected double length; + protected final Vertex target; + protected final Vertex source; + + public Edge(Vertex source, T target) { + this(source, new Vertex<>(target)); + } + + public Edge(Vertex source, Vertex target) { + this.target = target; + this.source = source; + this.length = source.getEntry().getDistance(target.getEntry()); + } + + public double getLength(){ + return length; + } + + public boolean isConnect(T other){ + return target.getEntry().equals(other); + } + + public boolean isConnect(Vertex target){ + return getTarget().equals(target); + } + + public Vertex getTarget(){ + return target; + } + + public Vertex getSource() { + return source; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Edge edge = (Edge) o; + + return source.equals(edge.source) && target.equals(edge.target); + + } + + @Override + public int hashCode() { + int result = target.hashCode(); + result = 31 * result + source.hashCode(); + return result; + } + + @Override + public String toString() { + return source.toString() + " -> " + target.toString(); + } +} diff --git a/core/src/main/java/ru/trader/graph/Graph.java b/core/src/main/java/ru/trader/graph/Graph.java new file mode 100644 index 0000000..d9904df --- /dev/null +++ b/core/src/main/java/ru/trader/graph/Graph.java @@ -0,0 +1,182 @@ +package ru.trader.graph; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +public class Graph> { + + @FunctionalInterface + public interface PathConstructor> { + Path build(Vertex source); + } + + private final static Logger LOG = LoggerFactory.getLogger(Graph.class); + + private final Vertex root; + private final HashMap> vertexes; + + private final double stock; + private final double maxDistance; + private final boolean withRefill; + private final PathConstructor pathFabric; + + + public Graph(T start, Collection set, double stock, int maxDeep) { + this(start, set, stock, stock, false, maxDeep, Path::new); + } + + public Graph(T start, Collection set, double stock, double maxDistance, int maxDeep) { + this(start, set, stock, maxDistance, true, maxDeep, Path::new); + } + + public Graph(T start, Collection set, double stock, boolean withRefill, int maxDeep) { + this(start, set, stock, stock, withRefill, maxDeep, Path::new); + } + + public Graph(T start, Collection set, double stock, boolean withRefill, int maxDeep, PathConstructor pathFabric) { + this(start, set, stock, stock, withRefill, maxDeep, pathFabric); + } + + public Graph(T start, Collection set, double stock, double maxDistance, boolean withRefill, int maxDeep, PathConstructor pathFabric) { + this.maxDistance = maxDistance; + this.stock = stock; + this.withRefill = withRefill; + this.pathFabric = pathFabric; + root = new Vertex<>(start); + root.setLevel(maxDeep); + vertexes = new HashMap<>(); + vertexes.put(root.getEntry(), root); + buildGraph(root, set, maxDeep-1, stock); + } + + private void buildGraph(Vertex vertex, Collection set, int deep, double limit) { + LOG.trace("Build graph from {}, limit {}, deep {}", vertex, limit, deep); + for (T entry : set) { + if (entry == vertex.getEntry()) continue; + double distance = vertex.getEntry().getDistance(entry); + if (distance <= this.maxDistance){ + if (withRefill && distance > limit && !vertex.getEntry().canRefill()){ + LOG.trace("Vertex {} is far away, {}", entry, distance); + continue; + } + Vertex next = vertexes.get(entry); + if (next == null){ + LOG.trace("Is new vertex"); + next = new Vertex<>(entry); + vertexes.put(entry, next); + } + LOG.trace("Add edge from {} to {}", vertex, next); + Edge edge = new Edge<>(vertex, next); + double nextLimit = withRefill ? limit - edge.getLength(): stock; + if (nextLimit < 0) { + LOG.trace("Refill"); + nextLimit = stock - edge.getLength(); + } + vertex.addEdge(edge); + // If level >= deep when vertex already added on upper deep + if (next.getLevel() < deep){ + next.setLevel(vertex.getLevel()-1); + if (deep > 0){ + buildGraph(next, set, deep-1, nextLimit); + } + } + } + } + LOG.trace("End build graph from {} on deep {}", vertex, deep); + } + + public boolean isAccessible(T entry){ + return vertexes.containsKey(entry); + } + + public Vertex getVertex(T entry){ + return vertexes.get(entry); + } + + public Collection> getPathsTo(T entry, boolean all){ + Vertex target = getVertex(entry); + return findPaths(pathFabric.build(root), target, root.getLevel()-1, stock, all); + } + + + private Collection> findPaths(Path head, Vertex target, int deep, double limit, boolean all){ + Collection> paths = new ArrayList<>(); + if (target == null) return paths; + boolean found =false; + Vertex source = head.getTarget(); + LOG.trace("Find path to deep from {} to {}, deep {}, limit {}, head {}", source, target, deep, limit, head); + Edge edge = source.getEdge(target); + if (edge != null ){ + if (!(withRefill && Math.min(limit, maxDistance) < edge.getLength() && !source.getEntry().canRefill())){ + found = true; + Path path = head.connectTo(edge, limit < edge.getLength()); + path.finish(); + LOG.trace("Last edge find, add path {}", path); + paths.add(path); + } + } + if ((all || !found) && deep > 0 ){ + if (source.getEdgesCount() > 0){ + LOG.trace("Search around"); + for (Edge next : source.getEdges()) { + if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue; + if (head.contains(next)) continue; + // target already added if source consist edge + if (next.isConnect(target)) continue; + Path path = head.connectTo(next, limit < next.getLength()); + double nextLimit = withRefill ? limit - next.getLength(): stock; + // refill + if (nextLimit < 0 ) nextLimit = maxDistance - next.getLength(); + paths.addAll(findPaths(path, target, deep - 1, nextLimit, all)); + if (!all && !paths.isEmpty()) break; + } + } + } + return paths; + } + + + public Path getFastPathTo(T entry){ + Vertex target = getVertex(entry); + return findFastPath(pathFabric.build(root), target, target.getLevel()+1, stock); + } + + private Path findFastPath(Path head, Vertex target, int deep, double limit) { + Vertex source = head.getTarget(); + LOG.trace("Find fast path from {} to {}, deep {}, limit {}, head {}", source, target, deep, limit, head); + if (deep == source.getLevel()){ + for (Edge next : source.getEdges()) { + if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue; + if (head.contains(next)) continue; + if (next.isConnect(target)) { + Path path = head.connectTo(next, limit < next.getLength()); + path.finish(); + LOG.trace("Last edge find, path {}", path); + return path; + } + } + } + if (deep < source.getLevel()){ + LOG.trace("Search around"); + for (Edge next : source.getEdges()) { + if (next.getTarget().getLevel() >= source.getLevel()) continue; + if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue; + Path path = head.connectTo(next, limit < next.getLength()); + double nextLimit = withRefill ? limit - next.getLength(): stock; + // refill + if (nextLimit < 0 ) nextLimit = stock - next.getLength(); + Path res = findFastPath(path, target, deep, nextLimit); + if (res != null) return res; + } + } + return null; + } + + public T getRoot() { + return root.getEntry(); + } +} diff --git a/core/src/main/java/ru/trader/graph/Path.java b/core/src/main/java/ru/trader/graph/Path.java new file mode 100644 index 0000000..10413a1 --- /dev/null +++ b/core/src/main/java/ru/trader/graph/Path.java @@ -0,0 +1,95 @@ +package ru.trader.graph; + +public class Path> { + private final Path head; + private final Vertex target; + private boolean refill; + + + public Path(Vertex source) { + this.head = null; + this.target = source; + this.refill = false; + } + + protected Path(Path head, Vertex vertex, boolean refill) { + this.head = head; + this.target = vertex; + this.refill = refill; + } + + public Path connectTo(Edge edge, boolean refill){ + return new Path<>(this, edge.getTarget(), refill); + } + + public void finish(){ + finish(target); + } + + protected void finish(Vertex target){ + if (!isRoot()){ + head.finish(target); + if (target != head.target) head.finish(); + } + } + + public boolean isRoot(){ + return head == null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Path)) return false; + + Path path = (Path) o; + return (isRoot() ? path.isRoot() : head.equals(path.head)) && target.equals(path.target); + + } + + @Override + public int hashCode() { + int result = head != null ? head.hashCode() : 0; + result = 31 * result + target.hashCode(); + return result; + } + + @Override + public String toString(){ + if (isRoot()) return target.getEntry().toString(); + final StringBuilder sb = new StringBuilder(head.toString()); + if (refill) sb.append("(R)"); + sb.append(" -> ").append(target.getEntry()); + return sb.toString(); + } + + public boolean contains(Edge edge) { + return target.equals(edge.getTarget()) || (!isRoot() && head.contains(edge)); + } + + @SafeVarargs + public static > Path toPath(T... items){ + T s = items[0]; + Path path = new Path<>(new Vertex<>(s)); + for (int i = 1; i < items.length; i++) { + T t = items[i]; + path = new Path<>(path, new Vertex<>(t), false); + s = t; + } + return path; + } + + public Vertex getTarget() { + return target; + } + + public boolean isRefill(){ + return refill; + } + + protected Path getHead(){ + return head; + } + + +} diff --git a/core/src/main/java/ru/trader/graph/PathRoute.java b/core/src/main/java/ru/trader/graph/PathRoute.java new file mode 100644 index 0000000..f3eaf70 --- /dev/null +++ b/core/src/main/java/ru/trader/graph/PathRoute.java @@ -0,0 +1,96 @@ +package ru.trader.graph; + +import ru.trader.core.Offer; +import ru.trader.core.Order; +import ru.trader.core.Vendor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +public class PathRoute extends Path { + private final ArrayList orders = new ArrayList<>(); + + public PathRoute(Vertex source) { + super(source); + } + + protected PathRoute(Path head, Vertex vertex, boolean refill) { + super(head, vertex, refill); + } + + @Override + public Path connectTo(Edge edge, boolean refill) { + return new PathRoute(this.getCopy(), edge.getTarget(), refill); + } + + @Override + protected void finish(Vertex target) { + if (!isRoot()) { + if (!contains(target.getEntry())){ + updateOrders(target.getEntry()); + getHead().finish(target); + if (getHead().getTarget() != target) getHead().finish(); + } + } + } + + private boolean contains(Vendor buyer){ + for (Order order : orders) { + if (order.isBuyer(buyer)) return true; + } + return false; + } + + private void updateOrders(Vendor buyer){ + Vendor seller = getHead().getTarget().getEntry(); + for (Offer sell : seller.getAllSellOffers()) { + Offer buy = buyer.getBuy(sell.getItem()); + if (buy != null) orders.add(new Order(sell, buy)); + } + } + + public Collection getOrders() { + return orders; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (Order order : orders) { + if (sb.length() > 0) sb.append(", "); + sb.append(order.getBuy().getItem()); + sb.append(" (").append(order.getBuy().getVendor()).append(") "); + } + String o = sb.toString(); + sb = new StringBuilder(); + if (isRoot()){ + sb.append(getTarget().getEntry()); + if (o.length()>0) sb.append(" (").append(o).append(") "); + } else { + sb.append(getHead().toString()); + if (isRefill()) sb.append("(R)"); + if (o.length()>0) sb.append(" (").append(o).append(") "); + sb.append(" -> ").append(getTarget().getEntry()); + } + return sb.toString(); + } + + public Path getCopy(){ + Path res; + LinkedList> v = new LinkedList<>(); + Path p = this; + while (!p.isRoot()){ + v.add(p); + p = p.getHead(); + } + res = p; + Iterator> it = v.descendingIterator(); + while (it.hasNext()){ + p = it.next(); + res = new PathRoute(res, p.getTarget(), p.isRefill()); + } + return res; + } +} diff --git a/core/src/main/java/ru/trader/graph/Vertex.java b/core/src/main/java/ru/trader/graph/Vertex.java new file mode 100644 index 0000000..519fe26 --- /dev/null +++ b/core/src/main/java/ru/trader/graph/Vertex.java @@ -0,0 +1,83 @@ +package ru.trader.graph; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; + +public class Vertex> { + private final ArrayList> edges = new ArrayList<>(); + private final T entry; + private int level = -1; + + public Vertex(T entry) { + this.entry = entry; + } + + public T getEntry() { + return entry; + } + + public boolean isConnected(Vertex other){ + return isConnected(other.entry); + } + + public boolean isConnected(T other){ + return edges.stream().anyMatch((e) -> e.isConnect(other)); + } + + public void addEdge(Edge edge){ + if (edges.contains(edge)) return; + edges.add(edge); + } + + public Collection> getEdges() { + return edges; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Vertex vertex = (Vertex) o; + return entry.equals(vertex.entry); + + } + + @Override + public int hashCode() { + return entry.hashCode(); + } + + public void sortEdges(Comparator comparator){ + edges.sort(comparator); + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } + + public int getEdgesCount(){ + return edges.size(); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Vertex{"); + sb.append(entry); + sb.append(", lvl=").append(level); + sb.append('}'); + return sb.toString(); + } + + public Edge getEdge(Vertex target) { + for (Edge edge : edges) { + if (edge.isConnect(target)) return edge; + } + return null; + } +} diff --git a/core/src/test/java/ru/trader/core/ItemStatTest.java b/core/src/test/java/ru/trader/core/ItemStatTest.java index a2dccb2..e9b363f 100644 --- a/core/src/test/java/ru/trader/core/ItemStatTest.java +++ b/core/src/test/java/ru/trader/core/ItemStatTest.java @@ -3,9 +3,13 @@ package ru.trader.core; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ItemStatTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(ItemStatTest.class); + private final static Item ITEM1 = new Item("Item1"); @@ -29,12 +33,14 @@ public class ItemStatTest extends Assert { @Test public void testSell(){ + LOG.info("Start sell test"); assertEquals(itemSellStat.getAvg(), (10+20+30+40)/4, 0); assertEquals(itemSellStat.getBest().getPrice(), 10d, 0); } @Test public void testBuy(){ + LOG.info("Start buy test"); assertEquals(itemBuyStat.getAvg(), (100+200+300+400)/4, 0); assertEquals(itemBuyStat.getBest().getPrice(), 400d, 0); } diff --git a/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java b/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java new file mode 100644 index 0000000..e6ef193 --- /dev/null +++ b/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java @@ -0,0 +1,192 @@ +package ru.trader.core; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.trader.TestUtil; +import ru.trader.graph.Path; + +import java.util.Collection; + +public class MarketAnalyzerTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzerTest.class); + + private static Market market = new SimpleMarket(); + private static Vendor v1; + private static Vendor v2; + private static Vendor v3; + private static Vendor v4; + private static Vendor v5; + private static Vendor v6; + private static Vendor v7; + private static Vendor v8; + private static Vendor v9; + private static Vendor v10; + private static Vendor v11; + private static Item ITEM1 = new Item("ITEM1"); + private static Item ITEM2 = new Item("ITEM2"); + private static Item ITEM3 = new Item("ITEM3"); + + @Before + public void setUp() throws Exception { + v1 = new SimpleVendor("v1_x0y0z0"); + v2 = new SimpleVendor("v2_x1y0z0"); + v3 = new SimpleVendor("v3_x0y1z0"); + v4 = new SimpleVendor("v4_x0y0z1"); + v5 = new SimpleVendor("v5_x1y1z0"); + + v6 = new SimpleVendor("v6_x110y100z100"); + v7 = new SimpleVendor("v7_x115y100z100"); + v8 = new SimpleVendor("v8_x105y105z100"); + v9 = new SimpleVendor("v9_x100y115z100"); + v10 = new SimpleVendor("v10_x100y100z100"); + v11 = new SimpleVendor("v11_x105y105z105"); + + v1.setX(0); v1.setY(0); v1.setZ(0); + v2.setX(1); v2.setY(0); v2.setZ(0); + v3.setX(0); v3.setY(1); v3.setZ(0); + v4.setX(0); v4.setY(0); v4.setZ(1); + v5.setX(1); v5.setY(1); v5.setZ(0); + v6.setX(110); v6.setY(100); v6.setZ(100); + v7.setX(115); v7.setY(100); v7.setZ(100); + v8.setX(105); v8.setY(105); v8.setZ(100); + v9.setX(100); v9.setY(115); v9.setZ(100); + v10.setX(100); v10.setY(100); v10.setZ(100); + v11.setX(105); v11.setY(105); v11.setZ(105); + + market.add(v1); + market.add(v2); + market.add(v3); + market.add(v4); + market.add(v5); + market.add(v6); + market.add(v7); + market.add(v8); + market.add(v9); + market.add(v10); + market.add(v11); + + market.add(v6, new Offer(OFFER_TYPE.SELL, ITEM1, 100)); + market.add(v7, new Offer(OFFER_TYPE.SELL, ITEM1, 100)); + market.add(v9, new Offer(OFFER_TYPE.SELL, ITEM1, 100)); + market.add(v10, new Offer(OFFER_TYPE.SELL, ITEM1, 100)); + market.add(v6, new Offer(OFFER_TYPE.BUY, ITEM1, 50)); + market.add(v7, new Offer(OFFER_TYPE.BUY, ITEM1, 120)); + market.add(v9, new Offer(OFFER_TYPE.BUY, ITEM1, 200)); + market.add(v10, new Offer(OFFER_TYPE.BUY, ITEM1, 150)); + market.add(v9, new Offer(OFFER_TYPE.SELL, ITEM2, 100)); + market.add(v6, new Offer(OFFER_TYPE.BUY, ITEM2, 140)); + market.add(v7, new Offer(OFFER_TYPE.SELL, ITEM3, 154)); + market.add(v10, new Offer(OFFER_TYPE.BUY, ITEM3, 140)); + market.add(v11, new Offer(OFFER_TYPE.BUY, ITEM3, 500)); + + } + + + @Test + public void testPaths() throws Exception { + LOG.info("Start paths test"); + MarketAnalyzer analyzer = new MarketAnalyzer(market); + analyzer.setJumps(5);analyzer.setMaxDistance(1);analyzer.setStock(1); + + Collection> paths = analyzer.getPaths(v1, v2); + TestUtil.assertCollectionEquals(paths, Path.toPath(v1, v2)); + + paths = analyzer.getPaths(v1, v3); + TestUtil.assertCollectionEquals(paths, Path.toPath(v1, v3)); + + paths = analyzer.getPaths(v1, v4); + TestUtil.assertCollectionEquals(paths, Path.toPath(v1, v4)); + + paths = analyzer.getPaths(v1, v5); + assertTrue(paths.isEmpty()); + + paths = analyzer.getPaths(v2, v5); + TestUtil.assertCollectionEquals(paths, Path.toPath(v2, v5)); + + paths = analyzer.getPaths(v4, v3); + assertTrue(paths.isEmpty()); + } + + @Test + public void testPathsWithStock() throws Exception { + LOG.info("Start paths with stock test"); + MarketAnalyzer analyzer = new MarketAnalyzer(market); + analyzer.setJumps(5);analyzer.setMaxDistance(1);analyzer.setStock(2); + + Collection> paths = analyzer.getPaths(v1, v2); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v2)); + + paths = analyzer.getPaths(v1, v3); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v3)); + + paths = analyzer.getPaths(v1, v4); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v4)); + + paths = analyzer.getPaths(v1, v5); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v2, v5), Path.toPath(v1, v3, v5)); + + paths = analyzer.getPaths(v2, v5); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v2, v5)); + + paths = analyzer.getPaths(v4, v3); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v4, v1, v3)); + } + + + @Test + public void testPathsWithStockAndRefill() throws Exception { + LOG.info("Start paths with stock and refill test"); + MarketAnalyzer analyzer = new MarketAnalyzer(market); + analyzer.setJumps(2);analyzer.setMaxDistance(10);analyzer.setStock(15); + + Collection> paths = analyzer.getPaths(v10, v6); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v6), Path.toPath(v10, v11, v6), + Path.toPath(v10, v8, v6)); + + paths = analyzer.getPaths(v1, v3); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v3), Path.toPath(v1, v2, v3), + Path.toPath(v1, v4, v3), Path.toPath(v1, v5, v3) + ); + } + + @Test + public void testPathsWithStockAndRefill2() throws Exception { + LOG.info("Start paths with stock and refill test 2"); + MarketAnalyzer analyzer = new MarketAnalyzer(market); + analyzer.setJumps(3);analyzer.setMaxDistance(10);analyzer.setStock(15); + + Collection> paths = analyzer.getPaths(v10, v6); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v6), Path.toPath(v10, v11, v6), + Path.toPath(v10, v8, v6), Path.toPath(v10, v8, v11, v6)); + + paths = analyzer.getPaths(v10, v7); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v6, v7), Path.toPath(v10, v11, v6, v7), + Path.toPath(v10, v8, v6, v7) + ); + + paths = analyzer.getPaths(v10, v8); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v8), Path.toPath(v10, v11, v8), + Path.toPath(v10, v11, v6, v8), Path.toPath(v10, v6, v8), Path.toPath(v10, v6, v11, v8)); + + paths = analyzer.getPaths(v10, v9); + assertTrue(paths.isEmpty()); + + paths = analyzer.getPaths(v10, v10); + TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v11, v10), Path.toPath(v10, v6, v10), + Path.toPath(v10, v11, v6, v10), Path.toPath(v10, v6, v11, v10), + Path.toPath(v10, v8, v10), Path.toPath(v10, v8, v11, v10), + Path.toPath(v10, v8, v6, v10)); + } + + + + @After + public void tearDown() throws Exception { + market = new SimpleMarket(); + + } +} diff --git a/core/src/test/java/ru/trader/core/MarketTest1.java b/core/src/test/java/ru/trader/core/MarketTest1.java index 15df812..e64e386 100644 --- a/core/src/test/java/ru/trader/core/MarketTest1.java +++ b/core/src/test/java/ru/trader/core/MarketTest1.java @@ -3,8 +3,12 @@ package ru.trader.core; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MarketTest1 extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(MarketTest1.class); + private final static Item ITEM1 = new Item("Item1"); private final static Item ITEM2 = new Item("Item2"); private final static Item ITEM3 = new Item("Item3"); @@ -64,6 +68,7 @@ public class MarketTest1 extends Assert { @Test public void testBestSell(){ + LOG.info("Start best sell test"); Offer test = market.getStatSell(ITEM1).getBest(); assertEquals(test, bestSellOffer1); test = market.getStatSell(ITEM2).getBest(); @@ -74,6 +79,7 @@ public class MarketTest1 extends Assert { @Test public void testBestBuy(){ + LOG.info("Start best buy test"); Offer test = market.getStatBuy(ITEM1).getBest(); assertEquals(test, bestBuyOffer1); test = market.getStatBuy(ITEM2).getBest(); diff --git a/core/src/test/java/ru/trader/core/VendorTest.java b/core/src/test/java/ru/trader/core/VendorTest.java index e526fe2..44b9c04 100644 --- a/core/src/test/java/ru/trader/core/VendorTest.java +++ b/core/src/test/java/ru/trader/core/VendorTest.java @@ -3,9 +3,13 @@ package ru.trader.core; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class VendorTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(VendorTest.class); + private final static Item ITEM1 = new Item("Item1"); private final static Item ITEM2 = new Item("Item2"); private final static Offer SELL_OFFER = new Offer(OFFER_TYPE.SELL, ITEM1, 10); @@ -24,6 +28,7 @@ public class VendorTest extends Assert { @Test public void testAddSellOffer(){ + LOG.info("Start add sell offer test"); final Iterable offers = sellVendor.getAllSellOffers(); Offer test = offers.iterator().next(); assertEquals(test, SELL_OFFER); @@ -31,18 +36,21 @@ public class VendorTest extends Assert { @Test public void testAddSellOffer2(){ + LOG.info("Start add sell offer test2"); final Iterable offers = sellVendor.getAllBuyOffers(); assertFalse(offers.iterator().hasNext()); } @Test public void testAddBuyOffer(){ + LOG.info("Start add buy offer test"); final Iterable offers = buyVendor.getAllSellOffers(); assertFalse(offers.iterator().hasNext()); } @Test public void testAddBuyOffer2(){ + LOG.info("Start add buy offer test2"); final Iterable offers = buyVendor.getAllBuyOffers(); Offer test = offers.iterator().next(); assertEquals(test, BUY_OFFER); @@ -50,36 +58,42 @@ public class VendorTest extends Assert { @Test public void testGetSellOfferOnSellVendor(){ + LOG.info("Start get sell offer from sell vendor test"); Offer test = sellVendor.getSell(ITEM1); assertEquals(test, SELL_OFFER); } @Test public void testGetSellOfferOnBuyVendor(){ + LOG.info("Start get sell offer from buy vendor test"); Offer test = buyVendor.getSell(ITEM1); assertNull(test); } @Test public void testGetWrongItemSellOfferOnSellVendor(){ + LOG.info("Start get wrong item from sell vendor test"); Offer test = buyVendor.getSell(ITEM2); assertNull(test); } @Test public void testGetBuyOfferOnSellVendor(){ + LOG.info("Start get buy offer from sell vendor test"); Offer test = sellVendor.getBuy(ITEM1); assertNull(test); } @Test public void testGetBuyOffersOnBuyVendor(){ + LOG.info("Start get buy offer from buy vendor test"); Offer test = buyVendor.getBuy(ITEM1); assertEquals(test, BUY_OFFER); } @Test public void testGetWrongItemBuyOfferOnBuyVendor(){ + LOG.info("Start get wrong item from buy vendor test"); Offer test = sellVendor.getBuy(ITEM2); assertNull(test); } diff --git a/core/src/test/java/ru/trader/core/VendorTest2.java b/core/src/test/java/ru/trader/core/VendorTest2.java index 7e8bd85..01c83ff 100644 --- a/core/src/test/java/ru/trader/core/VendorTest2.java +++ b/core/src/test/java/ru/trader/core/VendorTest2.java @@ -3,11 +3,15 @@ package ru.trader.core; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ru.trader.TestUtil; import java.util.Collection; public class VendorTest2 extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(VendorTest2.class); + private final static Item ITEM1 = new Item("Item1"); private final static Item ITEM2 = new Item("Item2"); private final static Item ITEM3 = new Item("Item3"); @@ -42,24 +46,28 @@ public class VendorTest2 extends Assert { @Test public void testGetSellOffer(){ + LOG.info("Start get sell offer test"); final Offer test = sellVendor.getSell(ITEM1); assertEquals(test, DUBLE_SELL_OFFER1); } @Test public void testGetBuyOffer(){ + LOG.info("Start get buy offer test"); final Offer test = buyVendor.getBuy(ITEM1); assertEquals(test, DUBLE_BUY_OFFER1); } @Test public void testGetAllSellOffer(){ + LOG.info("Start get all sell offer test"); final Collection test = sellVendor.getAllSellOffers(); TestUtil.assertCollectionContainAll(test, DUBLE_SELL_OFFER1, SELL_OFFER2, SELL_OFFER3); } @Test public void testGetAllBuyOffer(){ + LOG.info("Start get all buy offer test"); final Collection test = buyVendor.getAllBuyOffers(); TestUtil.assertCollectionContainAll(test, DUBLE_BUY_OFFER1, BUY_OFFER3, BUY_OFFER2); } diff --git a/core/src/test/java/ru/trader/graph/GraphTest.java b/core/src/test/java/ru/trader/graph/GraphTest.java new file mode 100644 index 0000000..a686d59 --- /dev/null +++ b/core/src/test/java/ru/trader/graph/GraphTest.java @@ -0,0 +1,314 @@ +package ru.trader.graph; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.trader.TestUtil; + +import java.util.ArrayList; +import java.util.Collection; + +public class GraphTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(GraphTest.class); + + private final static ArrayList entrys = new ArrayList<>(); + private final static Point x1 = new Point("x1",-40); + private final static Point x2 = new Point("x2",-20); + private final static Point x3 = new Point("x3",-10, true); + private final static Point x4 = new Point("x4",-5, true); + private final static Point x5 = new Point("x5",0); + private final static Point x6 = new Point("x6",5); + private final static Point x7 = new Point("x7",20); + private final static Point x8 = new Point("x8",30); + private final static Point x9 = new Point("x9",40); + private final static Point x10 = new Point("x10",50); + + @Before + public void setUp() throws Exception { + entrys.add(x1); + entrys.add(x2); + entrys.add(x3); + entrys.add(x4); + entrys.add(x5); + entrys.add(x6); + entrys.add(x7); + entrys.add(x8); + entrys.add(x9); + entrys.add(x10); + } + + @Test + public void testBuild0() throws Exception { + LOG.info("Start graph build test0"); + + Graph graph = new Graph<>(x5, entrys, 4.9, 10); + // x5 + assertFalse(graph.isAccessible(x1)); + assertFalse(graph.isAccessible(x2)); + assertFalse(graph.isAccessible(x3)); + assertFalse(graph.isAccessible(x4)); + assertTrue(graph.isAccessible(x5)); + assertFalse(graph.isAccessible(x6)); + assertFalse(graph.isAccessible(x7)); + assertFalse(graph.isAccessible(x8)); + assertFalse(graph.isAccessible(x9)); + assertFalse(graph.isAccessible(x10)); + } + + + @Test + public void testBuild1() throws Exception { + LOG.info("Start graph build test1"); + Graph graph = new Graph<>(x5, entrys, 5.1, true, 2); + // x5 <-> x4 <-refill-> x3, x5 -> x6 + assertFalse(graph.isAccessible(x1)); + assertFalse(graph.isAccessible(x2)); + assertTrue(graph.isAccessible(x3)); + assertTrue(graph.isAccessible(x4)); + assertTrue(graph.isAccessible(x5)); + assertTrue(graph.isAccessible(x6)); + assertFalse(graph.isAccessible(x7)); + assertFalse(graph.isAccessible(x8)); + assertFalse(graph.isAccessible(x9)); + assertFalse(graph.isAccessible(x10)); + + Vertex x = graph.getVertex(x5); + // x5 -> x4, x5 -> x6 + checkEdges(x, new Point[]{x4, x6}, new Point[]{x1, x2, x3, x7, x8, x9, x10}); + // x4 -> x5 + x = graph.getVertex(x4); + checkEdges(x, new Point[]{x5, x3}, new Point[]{x1, x2, x6, x7, x8, x9, x10}); + // x6 <- x5 + x = graph.getVertex(x6); + checkEdges(x, new Point[]{}, new Point[]{x1, x2, x3, x4, x5, x7, x8, x9, x10}); + + } + + private void checkEdges(Vertex vertex, Point[] trueEdge, Point[] falseEdge){ + for (Point point : trueEdge) { + assertTrue(String.format("%s must have edge to %s", vertex, point), vertex.isConnected(point)); + } + for (Point point : falseEdge) { + assertFalse(String.format("%s must not have edge to %s", vertex, point), vertex.isConnected(point)); + } + } + + @Test + public void testBuild2() throws Exception { + LOG.info("Start graph build test2"); + Graph graph = new Graph<>(x5, entrys, 5.1, 3); + // x5 <-> x4 <-> x3, x5 <-> x6 + assertFalse(graph.isAccessible(x1)); + assertFalse(graph.isAccessible(x2)); + assertTrue(graph.isAccessible(x3)); + assertTrue(graph.isAccessible(x4)); + assertTrue(graph.isAccessible(x5)); + assertTrue(graph.isAccessible(x6)); + assertFalse(graph.isAccessible(x7)); + assertFalse(graph.isAccessible(x8)); + assertFalse(graph.isAccessible(x9)); + assertFalse(graph.isAccessible(x10)); + + Vertex x = graph.getVertex(x5); + // x5 -> x4, x5 -> x6 + checkEdges(x, new Point[]{x4, x6}, new Point[]{x1, x2, x3, x7, x8, x9, x10}); + // x3 -> x4 + x = graph.getVertex(x3); + checkEdges(x, new Point[]{x4}, new Point[]{x1, x2, x5, x6, x7, x8, x9, x10}); + // x4 -> x5, x4 -> x3 + x = graph.getVertex(x4); + checkEdges(x, new Point[]{x3, x5}, new Point[]{x1, x2, x6, x7, x8, x9, x10}); + // x6 -> x5 + x = graph.getVertex(x6); + checkEdges(x, new Point[]{x5}, new Point[]{x1, x2, x3, x4, x7, x8, x9, x10}); + } + + + @Test + public void testBuild3() throws Exception { + LOG.info("Start graph build test3"); + Graph graph = new Graph<>(x5, entrys, 5.1, 3); + // x5 <-> x4 <-> x3, x5 <-> x6 + assertFalse(graph.isAccessible(x1)); + assertFalse(graph.isAccessible(x2)); + assertTrue(graph.isAccessible(x3)); + assertTrue(graph.isAccessible(x4)); + assertTrue(graph.isAccessible(x5)); + assertTrue(graph.isAccessible(x6)); + assertFalse(graph.isAccessible(x7)); + assertFalse(graph.isAccessible(x8)); + assertFalse(graph.isAccessible(x9)); + assertFalse(graph.isAccessible(x10)); + + Vertex x = graph.getVertex(x5); + // x5 -> x4, x5 -> x6 + checkEdges(x, new Point[]{x4, x6}, new Point[]{x1, x2, x3, x7, x8, x9, x10}); + // x3 -> x4 + x = graph.getVertex(x3); + checkEdges(x, new Point[]{x4}, new Point[]{x1, x2, x5, x6, x7, x8, x9, x10}); + // x4 -> x5, x4 -> x3 + x = graph.getVertex(x4); + checkEdges(x, new Point[]{x3, x5}, new Point[]{x1, x2, x6, x7, x8, x9, x10}); + // x6 -> x5 + x = graph.getVertex(x6); + checkEdges(x, new Point[]{x5}, new Point[]{x1, x2, x3, x4, x7, x8, x9, x10}); + + + } + + + @Test + public void testBuild4() throws Exception { + LOG.info("Start graph build test4"); + Graph graph = new Graph<>(x5, entrys, 15.1, 3); + // x5 <-> x4 <-> x3 -> x2, x5 <-> x6 <-> x7 -> x8 + // x5 <-> x3, x5 <-> x4 <-> x2, x3 <-> x6, x4 <-> x6 + assertFalse(graph.isAccessible(x1)); + assertTrue(graph.isAccessible(x2)); + assertTrue(graph.isAccessible(x3)); + assertTrue(graph.isAccessible(x4)); + assertTrue(graph.isAccessible(x5)); + assertTrue(graph.isAccessible(x6)); + assertTrue(graph.isAccessible(x7)); + assertTrue(graph.isAccessible(x8)); + assertFalse(graph.isAccessible(x9)); + assertFalse(graph.isAccessible(x10)); + + Vertex x = graph.getVertex(x5); + // x5 -> x4, x5 -> x3, x5 -> x6 + checkEdges(x, new Point[]{x3, x4, x6}, new Point[]{x1, x2, x7, x8, x9, x10}); + // x2 -> x3, x2 -> x4 + x = graph.getVertex(x2); + checkEdges(x, new Point[]{x3, x4}, new Point[]{x1, x5, x6, x7, x8, x9, x10}); + // x3 -> x4, x3 -> x2, x3 -> x5, x3 -> x6 + x = graph.getVertex(x3); + checkEdges(x, new Point[]{x2, x4, x5, x6}, new Point[]{x1, x7, x8, x9, x10}); + // x4 -> x5, x4 -> x3, x4 -> x2, x4 -> x6 + x = graph.getVertex(x4); + checkEdges(x, new Point[]{x2, x3, x5, x6}, new Point[]{x1, x7, x8, x9, x10}); + // x6 -> x5, x6 -> x7, x6 -> x3, x6 -> x4 + x = graph.getVertex(x6); + checkEdges(x, new Point[]{x5, x7, x3, x4}, new Point[]{x1, x2, x8, x9, x10}); + // x7 -> x6, x7 -> x8 + x = graph.getVertex(x7); + checkEdges(x, new Point[]{x6, x8}, new Point[]{x1, x2, x3, x4, x5, x9, x10}); + // x8 <- x7 + x = graph.getVertex(x8); + checkEdges(x, new Point[]{}, new Point[]{x1, x2, x3, x4, x5, x6, x7, x9, x10}); + + } + + + @Test + public void testGetPaths() throws Exception { + LOG.info("Start get paths test"); + Graph graph = new Graph<>(x5, entrys, 5.1, 2); + // x5 <-> x4, x5 <-> x6 + + Collection> paths = graph.getPathsTo(x4, true); + TestUtil.assertCollectionEquals(paths, Path.toPath(x5, x4)); + + paths = graph.getPathsTo(x6, true); + TestUtil.assertCollectionEquals(paths, Path.toPath(x5, x6)); + + paths = graph.getPathsTo(x7, true); + assertEquals(paths.size(), 0); + + } + + @Test + public void testGetPaths2() throws Exception { + LOG.info("Start get paths test2"); + Graph graph = new Graph<>(x5, entrys, 15.1, 3); + // x5 <-> x4 <-> x3 <-> x2, x5 <-> x6 <-> x7 <-> x8 + // x5 <-> x3, x4 <-> x2, x3 <-> x6, x4 <-> x6 + + Collection> paths = graph.getPathsTo(x8, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x6, x7, x8)); + + paths = graph.getPathsTo(x7, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x6, x7), Path.toPath(x5, x4, x6, x7), Path.toPath(x5, x3, x6, x7)); + + paths = graph.getPathsTo(x7, false); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x3, x6, x7)); + + paths = graph.getPathsTo(x4, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x4), Path.toPath(x5, x6, x4), Path.toPath(x5, x3, x4), + Path.toPath(x5, x6, x3, x4), Path.toPath(x5, x3, x2, x4), Path.toPath(x5, x3, x6, x4)); + + + paths = graph.getPathsTo(x5, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x4, x5), Path.toPath(x5, x4, x6, x5), Path.toPath(x5, x4, x3, x5), + Path.toPath(x5, x6, x5), Path.toPath(x5, x6, x4, x5), Path.toPath(x5, x6, x3, x5), Path.toPath(x5, x3, x5), + Path.toPath(x5, x3, x4, x5), Path.toPath(x5, x3, x6, x5)); + + + Path fast = graph.getFastPathTo(x8); + assertEquals(fast, Path.toPath(x5, x6, x7, x8)); + + fast = graph.getFastPathTo(x7); + assertEquals(fast, Path.toPath(x5, x6, x7)); + + fast = graph.getFastPathTo(x4); + assertEquals(fast, Path.toPath(x5, x4)); + } + + + @Test + public void testGetRefillPaths() throws Exception { + LOG.info("Start get refill paths"); + Graph graph = new Graph<>(x5, entrys, 10.1, 3); + // x5 <-> x4 <- refill -> x3 <- refill -> x2, x5 <-> x6 + // x5 <-> x3 <- refill -> x2, x5 <-> x4 <- refill -> x6 + + Collection> paths = graph.getPathsTo(x1, true); + assertTrue(paths.isEmpty()); + + paths = graph.getPathsTo(x2, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x4, x3, x2), Path.toPath(x5, x3, x2)); + + paths = graph.getPathsTo(x6, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x6), Path.toPath(x5, x4, x6), Path.toPath(x5, x3, x4, x6)); + + Path fast = graph.getFastPathTo(x2); + assertEquals(fast, Path.toPath(x5, x3, x2)); + + } + + @Test + public void testGetRefillPaths2() throws Exception { + LOG.info("Start get refill paths 2 "); + Graph graph = new Graph<>(x5, entrys, 15.1, true, 4); + // x5 <-> x4 <-> x3 - refill -> x2, + // x5 <-> x6 <-> x4 <-refill -> x2 + // x5 <-> x3 <- refill -> x2 + // x5 <-> x4 <- refill -> x6 + + Collection> paths = graph.getPathsTo(x1, true); + assertTrue(paths.isEmpty()); + + paths = graph.getPathsTo(x2, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x3, x4, x2), Path.toPath(x5, x3, x2), + Path.toPath(x5, x4, x3, x2), Path.toPath(x5, x4, x2), + Path.toPath(x5, x6, x4, x2), Path.toPath(x5, x6, x4, x3, x2)); + + paths = graph.getPathsTo(x6, true); + TestUtil.assertCollectionContainAll(paths, Path.toPath(x5, x6), Path.toPath(x5, x4, x6), + Path.toPath(x5, x3, x4, x6), Path.toPath(x5, x3, x6), Path.toPath(x5, x4, x3, x6)); + + paths = graph.getPathsTo(x7, true); + assertTrue(paths.isEmpty()); + + Path fast = graph.getFastPathTo(x2); + assertEquals(fast, Path.toPath(x5, x3, x2)); + + } + + @After + public void tearDown() throws Exception { + entrys.clear(); + } +} diff --git a/core/src/test/java/ru/trader/graph/Point.java b/core/src/test/java/ru/trader/graph/Point.java new file mode 100644 index 0000000..f68f026 --- /dev/null +++ b/core/src/test/java/ru/trader/graph/Point.java @@ -0,0 +1,45 @@ +package ru.trader.graph; + +public class Point implements Connectable { + private int x; + private String name; + private boolean refill; + + public Point(String name, int x) { + this(name, x, false); + } + + public Point(String name, int x, boolean refill) { + this.x = x; + this.name = name; + this.refill = refill; + } + + @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; + } + + @Override + public int hashCode() { + return x; + } + + @Override + public double getDistance(Point other) { + return Math.abs(x-other.x); + } + + @Override + public boolean canRefill() { + return refill; + } + + @Override + public String toString() { + return name; + } +} diff --git a/core/src/test/java/ru/trader/graph/VertexTest.java b/core/src/test/java/ru/trader/graph/VertexTest.java new file mode 100644 index 0000000..5532749 --- /dev/null +++ b/core/src/test/java/ru/trader/graph/VertexTest.java @@ -0,0 +1,30 @@ +package ru.trader.graph; + +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VertexTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(VertexTest.class); + + private final static Point x1 = new Point("x1",1); + private final static Point x2 = new Point("x2",4); + private final static Point x3 = new Point("x3",-2); + private final static Point x4 = new Point("x4",5); + + + @Test + public void testContains() throws Exception { + LOG.info("Start vertex contains test"); + + Vertex vertex = new Vertex<>(x1); + vertex.addEdge(new Edge<>(vertex, new Vertex<>(x2))); + vertex.addEdge(new Edge<>(vertex, x3)); + + assertFalse("Vertex must contains entry",vertex.isConnected(x1)); + assertTrue("Vertex must contains entry",vertex.isConnected(new Vertex<>(x3))); + assertTrue("Vertex must contains entry",vertex.isConnected(x2)); + assertFalse("Vertex not must contains entry", vertex.isConnected(new Vertex<>(x4))); + } +} diff --git a/core/src/test/java/ru/trader/store/LoadTest.java b/core/src/test/java/ru/trader/store/LoadTest.java index 8e6bf37..c337d81 100644 --- a/core/src/test/java/ru/trader/store/LoadTest.java +++ b/core/src/test/java/ru/trader/store/LoadTest.java @@ -2,6 +2,8 @@ package ru.trader.store; import org.junit.Assert; import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; import ru.trader.core.Market; @@ -10,9 +12,11 @@ import java.io.IOException; import java.io.InputStream; public class LoadTest extends Assert { + private final static Logger LOG = LoggerFactory.getLogger(LoadTest.class); @Test public void testLoad(){ + LOG.info("Start world load test"); InputStream is = getClass().getResourceAsStream("/test.xml"); Market world; try { diff --git a/core/src/test/resources/log4j.properties b/core/src/test/resources/log4j.properties new file mode 100644 index 0000000..c9817f0 --- /dev/null +++ b/core/src/test/resources/log4j.properties @@ -0,0 +1,6 @@ +log4j.rootLogger = INFO, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%p: %d{dd.MM.yyyy HH:mm:ss} (%F:%L) - %m%n +