using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Channels;
using System.Threading.Tasks;
public class Message
{
public Message(int _time, int _code, int _from, int _to, int _tok, int _pay)
{
(time, code, from, to, tok, pay) = (_time, _code, _from, _to, _tok, _pay);
}
public int time; public int code; public int from; public int to; public int tok; public int pay;
public readonly static int CodeReceive = 1;
public readonly static int CodeSend = 2;
public readonly static int TokForward = 1; // fan-out
public readonly static int TokReturn = 2; // fan-in
// public readonly static int TokStop = 3; // stop
}
public class Node
{
public Node(int self, int[] neigh)
{
this.self = self;
this.neigh = neigh;
}
int self;
int[] neigh;
int parent = -1;
int rec = 0;
int size = 1;
public Message[] Process(Message[] msgs)
{
//receive inbound messages
//process
//returns outbound messages
var clock = msgs[0].time;
var msgsout = Enumerable.Empty
if (parent == -1)
{
//msgs = msgs.OrderBy (m => Array.IndexOf (neigh, m.from)) .ToArray (); // -1 from 0
//parent = msgs[0].from;
//if (parent == 0) rec = -1;
var index = msgs.Min(m => Array.IndexOf(neigh, m.from));
if (index == -1)
{
parent = 0;
rec += -1;
}
else
{
parent = neigh[index];
}
msgsout = neigh.Where(n => n != parent)
.Select(n => new Message(clock, Message.CodeSend, self, n, Message.TokForward, 0));
}
else
{
size += msgs.Select(m => m.pay).Sum();
}
rec += msgs.Length;
if (rec >= neigh.Length)
{
msgsout = msgsout.Prepend(new Message(clock, Message.CodeSend, self, parent, Message.TokReturn, size));
}
return msgsout.ToArray();
}
}
// NodeProxy to wrap thread communication logic
public class NodeProxy
{
private Node node;
public Channel
public NodeProxy(Node node)
{
this.node = node;
}
public void Handle(Message[] msgs)
{
var msgOut = this.node.Process(msgs);
channel.Writer.WriteAsync(msgOut);
}
}
public class Arcs
{
static IEnumerable
{
var line = “”;
while ((line = inp.ReadLine()) != null)
{
yield return line;
}
}
// read and store configuration
// initialise nodes
static void Config(TextReader inp)
{
var lines = ReadAllLines(inp)
.Select(line =>
{
var com = line.IndexOf(“//”);
return com < 0 ? line : line.Substring(0, com);
})
.Select(line => line.Trim())
.Where(line => line != “”)
.Select(line => line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries))
.ToArray();
var nlines = lines.TakeWhile(line => line[0] != “.”)
.Select(lines => lines.Select(item => int.Parse(item)).ToArray())
.ToArray();
var alines = lines.Skip(nlines.Count() + 1)
.Select(lines => lines.Select(item => int.Parse(item)).ToArray())
.ToArray();
Source = nlines[0][0];
neighs = new Dictionary
nodes = new Dictionary
nodesProxies = new Dictionary
delays = new Dictionary<(int, int), int>();
channel = Channel.CreateUnbounded
foreach (var line in nlines)
{
var n = line[0];
var ns = line[1..^0];
neighs[n] = ns;
nodes[n] = new Node(n, ns);
nodesProxies[n] = new NodeProxy(new Node(n, ns));
nodesProxies[n].channel = channel;
}
//nodes.Dump ();
foreach (var line in alines)
{
delays[(line[0], line[1])] = line[2];
if (MaxDelay < line[2]) MaxDelay = line[2];
}
//delays.Dump ();
}
static int Clock;
static int Source; // initiator
static int MaxDelay;
static int MessageCount;
static Dictionary
static Dictionary
static Dictionary
static Dictionary<(int, int), int> delays;
static Channel
static int[] Neigh(int n)
{ // not needed
return neighs.ContainsKey(n) ? neighs[n] : Array.Empty
}
static Node Node(int n)
{
return nodes[n];
}
static NodeProxy NodeProxy(int n)
{
return nodesProxies[n];
}
static int Delay(int n1, int n2)
{
return delays.ContainsKey((n1, n2)) ? delays[(n1, n2)] : delays[(0, 0)];
}
static void Print(Message m)
{
Console.WriteLine($” {m.time,3} {(m.code == 1 ? ” ” : “”)}{m.code,3}{(m.code == 2 ? ” ” : “”)} {m.from,3} {m.to,3} {m.tok,3} {m.pay,3}”);
}
// priority queue for organising messages
static Message[] Msgs;
static async Task DetermineSizeOfNetwork()
{
var reader = channel.Reader;
while (await reader.WaitToReadAsync())
{
var msgsin = Enumerable.Empty
Message[] msgs;
while (reader.TryRead(out msgs))
{
msgsin = msgsin.Concat(msgs);
}
msgs = msgsin.ToArray();
if (msgs.Length > 0 && msgs[0].to == 0)
{
Console.WriteLine();
Console.WriteLine($” {Clock,3} {Clock / MaxDelay,3} {MessageCount,3} {msgs[0].pay,3}”);
break;
}
MessageCount += msgs.Length;
var msgs2 = SortToArray(msgs);
for (var i = 0; i < msgs2.Length; i++)
{
var m = msgs2[i];
Print(m);
m.time += Delay(m.from, m.to);
}
Msgs = SortToArray(Msgs.Concat(msgs2));
Clock = Msgs[0].time;
var msgsout = Msgs.TakeWhile(m => m.time == Clock).ToArray();
for (var i = 0; i < msgsout.Length; i++)
{
var m = msgsout[i];
m.code = 1;
Print(m);
}
Msgs = Msgs[msgsout.Length..];
var msgsout_grouped = msgsout.GroupBy(m => m.to);
foreach (var mgroup in msgsout_grouped)
{
NodeProxy(mgroup.Key).Handle(mgroup.ToArray());
}
}
}
public static void Main()
{
try
{
Clock = 0;
// Source; // initiator
MaxDelay = 1;
MessageCount = 0;
// Linqpad stuff
// Directory.SetCurrentDirectory (Path.GetDirectoryName (Util.CurrentQueryPath));
//Config(new StreamReader(“a1-inp1.txt”));
Config (Console.In);
Msgs = Array.Empty
MessageCount = 0;
var m0 = new Message(Clock, 2, 0, Source, 1, 0);
NodeProxy(Source).Handle(new[] { m0 });
// sends and receives messages on behalf of nodes,
// adding required delays, and tracing
DetermineSizeOfNetwork();
}
catch (Exception ex)
{
Console.WriteLine($”*** {ex.Message}”);
}
}
static Message[] SortToArray(IEnumerable
{
return ms.OrderBy(m => (m.time, m.code, m.from, m.to, m.tok, m.pay)).ToArray();
}
}