feat: implemented Graph

This commit is contained in:
Andrey Terentev 2025-04-13 00:03:20 +07:00
parent bbcba20499
commit 35b6644dd0

View File

@ -0,0 +1,129 @@
package ru.dragonestia.msb3.api.debug;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.minestom.server.coordinate.Vec;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Graph {
private final static AtomicInteger freeId = new AtomicInteger(1);
private final Map<Integer, Node> nodes = new HashMap<>();
public Node addNode(Vec pos) {
var node = new Node(pos);
nodes.put(node.getId(), node);
return node;
}
public boolean addNodeLink(Node from, Node to) {
return from.addLink(to) && to.addLink(from);
}
public void removeLink(Node from, Node to) {
from.removeLink(to);
to.removeLink(from);
}
public void removeNode(Node node) {
nodes.remove(node.getId());
node.getLinks().forEach(other -> removeLink(other, node));
}
public Collection<Node> getNodes() {
return nodes.values();
}
public Optional<Node> findNode(int id) {
return Optional.ofNullable(nodes.get(id));
}
public SerializedGraph serialize() {
var nodes = new ArrayList<SerializedNode>();
var links = new HashSet<IntPair>();
for (var node: getNodes()) {
nodes.add(new SerializedNode(node.id, node.position.x(), node.position.y(), node.position.z()));
for (var otherNode: node.getLinks()) {
if (links.contains(new IntPair(otherNode.getId(), node.getId()))) continue;
links.add(new IntPair(node.getId(), otherNode.getId()));
}
}
return new SerializedGraph(nodes, links);
}
public static Graph deserialize(SerializedGraph serializedGraph) {
var graph = new Graph();
for (var node: serializedGraph.nodes) {
graph.addNode(new Vec(node.x(), node.y(), node.z()));
}
for (var link: serializedGraph.links) {
graph.addNodeLink(graph.findNode(link.a).orElseThrow(), graph.findNode(link.b).orElseThrow());
}
return graph;
}
@RequiredArgsConstructor
public static class Node {
@Getter private final int id = freeId.getAndIncrement();
@Getter private final Vec position;
private final Map<Node, Double> links = new HashMap<>();
private boolean addLink(Node node) {
if (id == node.getId()) return false;
return links.put(node, position.distance(node.position)) == null;
}
private void removeLink(Node node) {
links.remove(node);
node.links.remove(this);
}
public boolean hasLink(Node node) {
if (id == node.getId()) return true;
return links.containsKey(node);
}
public Set<Node> getLinks() {
return links.keySet();
}
public Collection<DistancePair> getLinksWithDistance() {
return links.entrySet().stream()
.map(entry -> new DistancePair(entry.getKey(), entry.getValue()))
.toList();
}
public double getDistanceTo(Node node) {
return links.getOrDefault(node, Double.NaN);
}
@Override
public int hashCode() {
return id;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null) return false;
if (obj instanceof Node other) {
return id == other.id;
}
return false;
}
}
public record SerializedGraph(List<SerializedNode> nodes, Set<IntPair> links) {}
public record SerializedNode(int id, double x, double y, double z) {}
public record IntPair(int a, int b) {}
public record DistancePair(Node node, double distance) {}
}