我没有拿到具体的题目,只是参考了http://www.cnblogs.com/deepleo/p/thoughtworks.html,希望没有理解错误。
我觉得这里的重点之一是语义分析,需要在运行时解析各个“外星文”
代码如下(比较潦草,也没错误处理,罪过罪过。。。):
ProblemOne.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Thoughtworks.Problems { class ProblemOne { class Roman { private List<RomanPrimitive> Primitives; public Roman() { Primitives = new List<RomanPrimitive>(); } private int _valueCache = 0; private bool _dirty = true; public int Calculate() { if (_dirty) { _valueCache = 0; var result = 0; var length = Primitives.Count(); for (int i = 0; i < length; i++) { var current = Primitives[i]; result += current.OctValue; if (i == length - 1) return result; var next = Primitives[i + 1]; if (current.OctValue < next.OctValue) { result = next.OctValue - result; i++; } else if (current.OctValue == next.OctValue) { if (!current.AllowRepeat) { throw new Exception(string.Format("{0} can't be repeated", current.Symbol)); } var count = 2; for (int j = i + 2; j < length; j++) { if (Primitives[j].Symbol != current.Symbol) break; count++; result += current.OctValue; i++; if (count > 3) { throw new Exception(string.Format("{0} can't be repeated more than 3 times", current.Symbol)); } } } } _valueCache = result; } return _valueCache; } public static Roman Parse(string str, Dictionary<string, RomanPrimitive> map) { var left = str.Split(' '); var number = new StringBuilder(); for (int i = 0; i < left.Length; i++) { number.Append(map[left[i]].Symbol); } var roman = Roman.Parse(number.ToString()); return roman; } public static Roman Parse(string str) { var roman = new Roman(); var chars = str.ToCharArray(); for (int i = 0; i < chars.Length; i++) { roman.Primitives.Add(RomanPrimitive.Parse(chars[i])); } return roman; } } class RomanPrimitive { private static ILookup<char, RomanPrimitive> Primitives = new List<RomanPrimitive>{ new RomanPrimitive('I', 1, true, true), new RomanPrimitive('V', 5), new RomanPrimitive('X', 10, true, true), new RomanPrimitive('L', 50), new RomanPrimitive('C', 100, true, true), new RomanPrimitive('D', 500), new RomanPrimitive('M', 1000, true), }.ToLookup(_=>_.Symbol); private RomanPrimitive(char symbol, int octValue, bool allowRepeat = false, bool allowSubtract = false) { Symbol = symbol; OctValue = octValue; AllowRepeat = allowRepeat; AllowSubtract = allowSubtract; } public int OctValue { get; private set; } public char Symbol { get; private set; } public bool AllowRepeat { get; private set; } public bool AllowSubtract { get; private set; } public static RomanPrimitive Parse(char Symbol) { if (!Primitives.Contains(Symbol)) return null; return Primitives[Symbol].First(); } } class Context { public string PrimUnit { get; set; } public Dictionary<string, RomanPrimitive> Primitives { get; set; } public Dictionary<string, double> Units { get; set; } public List<string> Questions { get; set; } public Context() { Primitives = new Dictionary<string, RomanPrimitive>(); Units = new Dictionary<string, double>(); Questions = new List<string>(); } } abstract class Parser { public Context Context { get; private set; } public Parser(Context ctx) { Context = ctx; } public abstract bool Parse(string input); } class PrimitiveParser : Parser { public PrimitiveParser(Context ctx) : base(ctx) { } public override bool Parse(string input) { var lexers = input.Split(new []{" is "}, StringSplitOptions.RemoveEmptyEntries); if (lexers.Count() != 2) return false; if (lexers[1].Length > 1) return false; var roman = RomanPrimitive.Parse(lexers[1][0]); if (roman == null) { throw new Exception("syntex error."); } var name = lexers[0].Trim(); Context.Primitives[name] = roman; return true; } } class UnitParser : Parser { public UnitParser(Context ctx) : base(ctx) { } public override bool Parse(string input) { var lexers = input.Split(new[] { " is " }, StringSplitOptions.RemoveEmptyEntries); if (lexers.Count() != 2) return false; var left = lexers[0].Split(' '); if (left.Length < 2) return false; var rValue = int.Parse(lexers[1].Split(' ')[0]); var primUnit = lexers[1].Split(' ')[1]; Context.PrimUnit = primUnit; var roman = Roman.Parse(String.Join(" ", left.Take(left.Length - 1)), Context.Primitives); var calculated = roman.Calculate(); var unit = left.Last(); var unitValue = (double)rValue / (double)calculated; Context.Units[unit] = unitValue; return true; } } class QuestionParser : Parser { public QuestionParser(Context ctx) : base(ctx) { } public override bool Parse(string input) { if (!input.EndsWith("?")) return false; Context.Questions.Add(input.Replace("?", "").Trim()); return true; } } abstract class Solver { public Context Context { get; private set; } public Solver(Context ctx) { Context = ctx; } public abstract bool Solve(string input, out string answer); } class UnitSolver : Solver { public UnitSolver(Context ctx) : base(ctx) { } public override bool Solve(string question, out string answer) { var primUnit = Context.PrimUnit; var qulifier = String.Format("how many {0} is", primUnit); if (!question.StartsWith(qulifier)) { answer = null; return false; } var body = question.Substring(qulifier.Length + 1); var lexers = body.Split(' '); var unit = lexers.Last().Trim(); var unitValue = Context.Units[unit]; var value = Roman.Parse(String.Join(" ", lexers.Take(lexers.Length - 1)), Context.Primitives).Calculate(); answer = value * unitValue + " " + primUnit; Console.WriteLine(body + " is " + answer); return true; } } class PrimitiveSolver : Solver { public PrimitiveSolver(Context ctx) : base(ctx) { } public override bool Solve(string question, out string answer) { var qulifier = "how much is"; if (!question.StartsWith(qulifier)) { answer = null; return false; } var body = question.Substring(qulifier.Length + 1); var value = Roman.Parse(body, Context.Primitives).Calculate(); answer = value.ToString(); Console.WriteLine(body + " is " + answer); return true; } } public static void Run(string[] input) { Console.WriteLine("Thinking...."); var ctx = new Context(); var parsers = new Parser[] { new PrimitiveParser(ctx), new UnitParser(ctx), new QuestionParser(ctx) }; var solvers = new Solver[] { new PrimitiveSolver(ctx), new UnitSolver(ctx) }; foreach (var cmd in input) { foreach (var parser in parsers) { try { if (parser.Parse(cmd)) { break; } } catch { } } } foreach (var cmd in ctx.Questions) { var solved = false; foreach (var solver in solvers) { string answer = ""; try { if (solver.Solve(cmd, out answer)) { solved = true; break; } } catch { } } if (!solved) { Console.WriteLine("I have no idea what you are talking about."); } } Console.WriteLine("done."); Console.ReadKey(); } } }
Program.cs
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Thoughtworks.Problems; namespace Thoughtworks { class Program { static void Main(string[] args) { using (TextReader reader = new StreamReader("Problems/Input")) { var lines = new List<string>(); string line = null; do { line = reader.ReadLine(); if (line == null) break; Console.WriteLine(line); lines.Add(line); } while (line != null); ProblemOne.Run(lines.ToArray()); } } } }
Input,位于Problems目录中
glob is I prok is V pish is X tegj is L glob glob Silver is 34 Credits glob prok Gold is 57800 Credits pish pish Iron is 3910 Credits how much is pish tegj glob glob ? how much is glob prok ? how many Credits is glob prok Silver ? how many Credits is glob prok Gold ? how many Credits is glob prok Iron ? how much wood could a woodchuck chuck if a woodchuck could chuck wood ?