I have this short program for simulating a random packet routing algorithm:
Packet.java
package net.coderodde.simulation.network;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* This class implements a packet being transmitted in the network.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Jun 23, 2016)
*/
public class Packet {
private final int sourceNetworkNodeId;
private final int targetNetworkNodeId;
private final List<NetworkNode> history = new ArrayList<>();
private int cycles;
public Packet(final int id,
final int sourceNetworkNodeId,
final int targetNetworkNodeId) {
this.sourceNetworkNodeId = sourceNetworkNodeId;
this.targetNetworkNodeId = targetNetworkNodeId;
}
public boolean isDelivered() {
if (history.isEmpty()) {
return false;
}
return history.get(history.size() - 1).getId() == targetNetworkNodeId;
}
public final void mark(final NetworkNode networkNode) {
history.add(networkNode);
}
public final void incrementCycleCounter() {
cycles++;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("[")
.append(sourceNetworkNodeId)
.append(" -> ")
.append(targetNetworkNodeId)
.append("; cycles: ")
.append(cycles)
.append("; history: [");
final Map<Integer, Integer> map = compressPath(history);
final Iterator<Map.Entry<Integer, Integer>> iterator =
map.entrySet().iterator();
if (iterator.hasNext()) {
final Map.Entry<Integer, Integer> entry = iterator.next();
if (entry.getValue() == 1) {
sb.append(entry.getKey());
} else {
sb.append(entry.getKey())
.append("(")
.append(entry.getValue())
.append(")");
}
}
while (iterator.hasNext()) {
final Map.Entry<Integer, Integer> entry = iterator.next();
sb.append(", ");
if (entry.getValue() == 1) {
sb.append(entry.getKey());
} else {
sb.append(entry.getKey())
.append("(")
.append(entry.getValue())
.append(")");
}
}
return sb.append("]]").toString();
}
private Map<Integer, Integer> compressPath(final List<NetworkNode> path) {
final Map<Integer, Integer> map = new LinkedHashMap<>();
for (final NetworkNode networkNode : path) {
final int networkNodeId = networkNode.getId();
map.put(networkNodeId, map.getOrDefault(networkNodeId, 0) + 1);
}
return map;
}
}
NetworkNode.java:
package net.coderodde.simulation.network;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Random;
/**
* This class implements a simulated network node. Each node maintains a queue
* of packets that have been received but not yet sent away.
*
* @author Rodion "rodde" Efremov
* @version 1.6 (Jun 23, 2016)
*/
public class NetworkNode {
private final int id;
private final List<NetworkNode> neighbors = new ArrayList<>();
private final Deque<Packet> queue = new ArrayDeque<>();
private final Random random = new Random();
private int maximumQueueLength;
public NetworkNode(final int id) {
this.id = id;
}
public final void connect(final NetworkNode node) {
Objects.requireNonNull(node, "The input node is null.");
if (!neighbors.contains(node)) {
neighbors.add(node);
node.neighbors.add(this);
}
}
public final List<NetworkNode> getNeighborList() {
return Collections.<NetworkNode>unmodifiableList(neighbors);
}
public final int getId() {
return id;
}
public void offetPacket(final Packet packet) {
queue.add(packet);
}
public void sendPacket() {
maximumQueueLength = Math.max(maximumQueueLength, queue.size());
for (final Packet packet : queue) {
packet.incrementCycleCounter();
packet.mark(this);
}
final Iterator<Packet> iterator = queue.iterator();
while (iterator.hasNext()) {
final Packet packet = iterator.next();
if (packet.isDelivered()) {
iterator.remove();
}
}
if (!queue.isEmpty()) {
final Packet packet = queue.removeFirst();
final NetworkNode nextNetworkNode = randomNeighbor();
nextNetworkNode.queue.addLast(packet);
}
}
@Override
public String toString() {
return "[ID = " + id + "; maximum queue length: " +
maximumQueueLength + "]";
}
private final NetworkNode randomNeighbor() {
return neighbors.get(random.nextInt(neighbors.size()));
}
}
Main.java:
package net.coderodde.simulation.network;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
private static final int NETWORK_SIZE = 10;
private static final int NUMBER_OF_LINKS = 50;
private static final int PACKETS = 30;
public static void main(final String[] args) {
final List<NetworkNode> network = createRandomNetwork(NETWORK_SIZE,
NUMBER_OF_LINKS);
final List<Packet> packets = createInitialPackets(network,
PACKETS);
while (somePacketsUndelivered(packets)) {
for (final NetworkNode networkNode : network) {
networkNode.sendPacket();
}
}
System.out.println("=== Packet statistics ===");
packets.forEach(System.out::println);
System.out.println();
System.out.println("=== Node statistics ===");
network.forEach(System.out::println);
}
private static boolean somePacketsUndelivered(final List<Packet> packets) {
for (final Packet packet : packets) {
if (!packet.isDelivered()) {
return true;
}
}
return false;
}
private static List<NetworkNode> createRandomNetwork(final int size,
final int edges) {
final List<NetworkNode> network = new ArrayList<>(size);
for (int id = 0; id < NETWORK_SIZE; ++id) {
network.add(new NetworkNode(id));
}
final Random random = new Random();
for (int i = 0; i < edges; ++i) {
network.get(random.nextInt(NETWORK_SIZE))
.connect(network.get(random.nextInt(NETWORK_SIZE)));
}
return network;
}
private static List<Packet>
createInitialPackets(final List<NetworkNode> network,
final int packets) {
final Random random = new Random();
final List<Packet> packetList = new ArrayList<>(packets);
for (int id = 0; id < packets; ++id) {
final NetworkNode source =
network.get(random.nextInt(network.size()));
final NetworkNode target =
network.get(random.nextInt(network.size()));
final Packet packet = new Packet(id,
source.getId(),
target.getId());
packetList.add(packet);
source.offetPacket(packet);
}
return packetList;
}
}
As always, any critique is much appreciated.