Skip to content

Instantly share code, notes, and snippets.

@konstantint
Last active October 27, 2022 15:36
Show Gist options
  • Save konstantint/f8c45b64342c56a6f86a77f945ac8b67 to your computer and use it in GitHub Desktop.
Save konstantint/f8c45b64342c56a6f86a77f945ac8b67 to your computer and use it in GitHub Desktop.
A program for adding ten numbers
// Source code for the post:
// https://www.quora.com/Can-you-write-a-program-for-adding-10-numbers/answer/Konstantin-Tretyakov
// http://fouryears.eu/2018/03/17/a-program-for-adding-10-numbers/
//
// Runs with the following config.xml:
// <Config>
// <InputProvider class="Enterprise.NumberSequenceProvider"/>
// <OutputConsumer class="Enterprise.PeanoNumberPrinter"/>
// <Solution class="Enterprise.TenNumberAddingSolution">
// <Strategy class="Enterprise.AdditionStrategy"/>
// </Solution>
// </Config>
using System;
using System.Linq;
using System.Xml.Linq;
using System.IO;
using System.Collections.Generic;
using System.Threading;
namespace Enterprise
{
interface IInputProvider {}
interface IOutput {}
interface ISolution {
IOutput add10(IInputProvider input);
}
interface IOutputConsumer {
void consumeOutput(IOutput output);
}
class SolutionFactory {
private XDocument cfg;
public SolutionFactory(string configFile) {
cfg = XDocument.Load(configFile);
}
public IInputProvider GetInputProvider() {
return Instantiate<IInputProvider>("InputProvider");
}
public IOutputConsumer GetOutputConsumer() {
return Instantiate<IOutputConsumer>("OutputConsumer");
}
public ISolution GetSolution() {
return Instantiate<ISolution>("Solution");
}
private T Instantiate<T>(string elementName) {
var typeName = cfg.Root.Element(elementName).Attribute("class").Value;
return (T)Activator.CreateInstance(Type.GetType(typeName));
}
}
interface INumber: IOutput {
INumber add(INumber other);
}
enum NumberOfANumber {
ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN
}
interface ITenNumbersProvider {
INumber GetNumber(NumberOfANumber noan);
}
delegate void NumberHandler(NumberOfANumber id, INumber n);
interface IAsynchronousInputProvider: IInputProvider {
void AddNumberListener(NumberHandler handler);
}
class SynchronizationAdapter: ITenNumbersProvider {
private Dictionary<NumberOfANumber, INumber> nums;
private ManualResetEvent allDataAvailableEvent;
public SynchronizationAdapter(IAsynchronousInputProvider ainput) {
nums = new Dictionary<NumberOfANumber, INumber>();
allDataAvailableEvent = new ManualResetEvent(false);
ainput.AddNumberListener(this.HandleIncomingNumber);
}
private void HandleIncomingNumber(NumberOfANumber id, INumber n) {
nums[id] = n;
if (Enum.GetValues(typeof(NumberOfANumber)).Cast<NumberOfANumber>()
.All(k => nums.ContainsKey(k))) allDataAvailableEvent.Set();
}
public INumber GetNumber(NumberOfANumber noan) {
allDataAvailableEvent.WaitOne();
return nums[noan];
}
}
interface IAdditionStrategy {
INumber fold(Func<NumberOfANumber, INumber> elements, Func<INumber, INumber, INumber> op);
}
class TenNumbersAddingSolution: ISolution {
private IAdditionStrategy strategy;
public TenNumbersAddingSolution() {
var cfg = XDocument.Load("config.xml");
var typeName = cfg.Root.Element("Solution").Element("Strategy").Attribute("class").Value;
strategy = (IAdditionStrategy)Activator.CreateInstance(Type.GetType(typeName));
}
public IOutput add10(IInputProvider input) {
var tenNumbers = new SynchronizationAdapter((IAsynchronousInputProvider)input);
return strategy.fold(i => tenNumbers.GetNumber(i), (x,y) => x.add(y));
}
}
class PeanoInteger: INumber {
public PeanoInteger Prev { get; private set; }
public PeanoInteger(PeanoInteger prev) { Prev = prev; }
public INumber add(INumber b) {
if (b == null) return this;
else return new PeanoInteger(this).add(((PeanoInteger)b).Prev);
}
}
class PeanoNumberPrinter: IOutputConsumer {
public void consumeOutput(IOutput p) {
for (var x = (PeanoInteger)p; x != null; x = x.Prev) Console.Write("1");
Console.WriteLine();
}
}
class NumberSequenceProvider: IAsynchronousInputProvider {
private event NumberHandler handler;
private ManualResetEvent handlerAvailable;
public NumberSequenceProvider() {
handlerAvailable = new ManualResetEvent(false);
new Thread(ProduceNumbers).Start();
}
public void AddNumberListener(NumberHandler nh) {
handler += nh;
handlerAvailable.Set();
}
private void ProduceNumbers() {
handlerAvailable.WaitOne();
PeanoInteger pi = null;
foreach (var v in Enum.GetValues(typeof(NumberOfANumber)).Cast<NumberOfANumber>()) {
pi = new PeanoInteger(pi);
handler(v, pi);
}
}
}
class AdditionStrategy: IAdditionStrategy {
public INumber fold(Func<NumberOfANumber, INumber> elements, Func<INumber, INumber, INumber> op) {
return Enum.GetValues(typeof(NumberOfANumber))
.Cast<NumberOfANumber>()
.Select(elements).Aggregate(op);
}
}
class Solution: ISolution {
public IOutput add10(IInputProvider input) {
return (IOutput)input;
}
}
class Program {
static void Main(string[] args) {
var sf = new SolutionFactory("config.xml");
var ip = sf.GetInputProvider();
var oc = sf.GetOutputConsumer();
var sol = sf.GetSolution();
var op = sol.add10(ip);
oc.consumeOutput(op);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment