using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.IO; namespace vyhodnoceni { public static class Program { public static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Parametry jsou dve jmena souboru oddelena mezerou: sit vstupni-data"); } else { string netFile = args[0]; string inputFile = args[1]; try { var net = Network.GetNetwork(netFile); net.ProcessFile(inputFile); } catch (Exception exception) { Console.WriteLine("Program skoncil chybou: {0}", exception.Message); } } } private static void PerformTests() { // jednoducha funkce k otestovani vsech dodanych siti string[] files = { "nevnorene1", "nevnorene2", "nevnorene3", "nevnorene4", "nevnorene5", "nevnorene6", "nevnorene7", "nevnorene8", "nevnorene9", "nevnoreneA", "vnorene1", "vnorene2", "vnorene3", "vnorene4", "vnorene5", "vnorene6", "vnorene7" }; foreach (var netFile in files) { string inputFile = netFile + ".in"; var net = Network.GetNetwork(netFile); net.Testing = true; net.ProcessFile(inputFile); string myResults = net.OutputData; string theirResults = new StreamReader(netFile + ".out").ReadToEnd(); Console.WriteLine("{0}: {1}", netFile, (myResults == theirResults) ? "OK" : "Failed"); } Console.ReadKey(); } } // vstup, vystup nebo hradlo public abstract class Node { protected bool? value = null; public virtual bool HasValue() { return value != null; } public virtual bool GetValue() { return this.value.Value; } public void Reset() { value = null; } } // vstup nebo vystup public class ConnectionPoint : Node { protected string id; protected void init(string id) { this.id = id; } } public class Input : ConnectionPoint { protected Output output = null; public Input(string id) { init(id); } // nastavi prislusny vystup, ze ktereho se ziskaji data public void SetOutput(Output output) { this.output = output; } public override bool HasValue() { return this.output.HasValue(); } public override bool GetValue() { return this.output.GetValue(); } public string GetId() { return this.id; } } public class Output : ConnectionPoint { public Output(string id) { init(id); } public void SetValue(bool value) { this.value = value; } } public abstract class Gate : Node { protected List inputs = new List { }; protected List outputs = new List { }; public void Add(Input input) { inputs.Add(input); } public void Add(Output output) { outputs.Add(output); } public bool Calculate() { // kontrola, jestli vsechny vstupy maji hodnotu foreach (var input in inputs) { if (!input.HasValue()) return false; } // vlastni vypocet this.value = CalculateInner(); if (this.value != null) { // jednoduche hradlo (jeden vystup) foreach (var output in outputs) { output.SetValue(this.value.Value); } } else { // vnorene hradlo (vice vystupu) var data = this.CalculateInnerComplex(); for (int i = 0; i < data.Length; i++) { outputs[i].SetValue(data[i]); } this.value = true; } return true; } // vlastni vypocet pro jednoducha hradla (s jednou vystupnii hodnotou) protected abstract bool? CalculateInner(); // vlastni vypocet pro vnorena hradla protected virtual bool[] CalculateInnerComplex() { throw new NotSupportedException(); } } public class AndGate : Gate { protected override bool? CalculateInner() { foreach (var input in inputs) { if (input.GetValue() == false) return false; } return true; } } public class OrGate : Gate { protected override bool? CalculateInner() { foreach (var input in inputs) { if (input.GetValue() == true) return true; } return false; } } public class XorGate : Gate { protected override bool? CalculateInner() { bool value = false; foreach (var input in inputs) { value ^= input.GetValue(); } return value; } } public class NotGate : Gate { protected override bool? CalculateInner() { return !inputs[0].GetValue(); } } public class ComplexGate : Gate { private Network network; public ComplexGate(string netFile) { network = Network.GetNetwork(netFile); } protected override bool? CalculateInner() { return null; } protected override bool[] CalculateInnerComplex() { var data = new bool[inputs.Count]; for (int i = 0; i < inputs.Count; i++) { data[i] = inputs[i].GetValue(); } return network.ProcessData(data); } } public class Network { private static Dictionary networks = new Dictionary { }; // vytvori sit nebo vrati drive vytvorenou public static Network GetNetwork(string netFile) { if (!networks.ContainsKey(netFile)) { networks[netFile] = new Network(netFile); } return networks[netFile]; } // hlavni vstupy se chovaji stejne jako vystupy uvnitr hradel (a naopak) private List globalInputs = new List { }; private List globalOutputs = new List { }; private List gates = new List { }; // seznamy vsech vstupu a vystupu private List inputs = new List { }; private Dictionary outputs = new Dictionary { }; // pro testovani public bool Testing { get; set; } public string OutputData { get; private set; } // zpracuje xml soubor a vytvori strukturu objektu private Network(string netFile) { Testing = false; var xml = new XmlDocument(); xml.Load(netFile); foreach (XmlElement item in xml.ChildNodes[0].ChildNodes) { switch (item.Name) { case "input": globalInputs.Add(CreateOutput(item)); break; case "output": globalOutputs.Add(CreateInput(item)); break; case "gate": gates.Add(CreateGate(item)); break; default: throw new NotSupportedException("Tag " + item.Name + " neni podporovany."); } } // spoji vstupy s prislusnimy vystupy foreach (var input in inputs) { string id = input.GetId(); if (!outputs.ContainsKey(id)) throw new Exception("Neexistuje vystupni prvek s id = '" + id + "'"); input.SetOutput(outputs[id]); } } // zpracuje vstupni soubor public void ProcessFile(string inputFile) { var reader = new StreamReader(inputFile); while (!reader.EndOfStream) { string inputLine = reader.ReadLine().Trim(); string outputLine = ProcessLine(inputLine); if (outputLine != null) { if (!Testing) { Console.WriteLine(outputLine); } else { OutputData += outputLine + "\r\n"; } } else { Console.WriteLine(""); } } reader.Close(); } // zpracuje radek vstupniho souboru private string ProcessLine(string inputLine) { if (inputLine.Length != globalInputs.Count) return null; var data = new bool[globalInputs.Count]; for (int i = 0; i < globalInputs.Count; i++) { data[i] = CharToBool(inputLine[i]); } var outputData = ProcessData(data); var outputLine = new StringBuilder(globalOutputs.Count); foreach (var item in outputData) { outputLine.Append(BoolToChar(item)); } return outputLine.ToString(); } // zpracuje vstupni data public bool[] ProcessData(bool[] data) { ResetNetwork(); // nastavi pocatecni hodnoty for (int i = 0; i < globalInputs.Count; i++) { globalInputs[i].SetValue(data[i]); } bool done = false; while (!done) { // spocita hodnoty hradel, pokud je to mozne bool changed = false; foreach (var gate in gates) { if (!gate.HasValue()) { changed |= gate.Calculate(); } } if (!changed) { // nic se nezmenilo, vypocet je tedy snad hotovy done = true; foreach (var output in globalOutputs) { done &= output.HasValue(); if (!done) break; } if (!done) { // vypocet neni hotovy throw new Exception("Spatna sit, nejde vyresit"); } } } // posbira vystupni data var outputData = new bool[globalOutputs.Count]; for (int i = 0; i < globalOutputs.Count; i++) { outputData[i] = globalOutputs[i].GetValue(); } return outputData; } // pripravi sit pro dalsi vypocet private void ResetNetwork() { foreach (var item in gates) { item.Reset(); } foreach (var item in outputs) { item.Value.Reset(); } } private char BoolToChar(bool value) { return value ? '1' : '0'; } private bool CharToBool(char ch) { switch (ch) { case '0': return false; case '1': return true; default: throw new NotSupportedException("Znak '" + ch + "' ve vstupnich datech neni podporovan."); } } private Input CreateInput(XmlElement item) { string id = item.Attributes["id"].Value; var input = new Input(id); inputs.Add(input); return input; } private Output CreateOutput(XmlElement item) { string id = item.Attributes["id"].Value; var output = new Output(id); outputs.Add(id, output); return output; } private Gate CreateGate(XmlElement item) { string type = item.Attributes["type"].Value; type = type.ToLower(); // vytvori branu Gate gate = null; switch (type) { case "and": gate = new AndGate(); break; case "or": gate = new OrGate(); break; case "xor": gate = new XorGate(); break; case "not": gate = new NotGate(); break; default: gate = new ComplexGate(type); break; } // prida brane vstupy a vystupy foreach (XmlElement child in item) { switch (child.Name) { case "input": gate.Add(CreateInput(child)); break; case "output": gate.Add(CreateOutput(child)); break; default: throw new NotSupportedException("Tag " + child.Name + " neni podporovany."); } } return gate; } } }