ThoughtWorks笔试题之Merchant's Guide To The Galaxy解析
我没有拿到具体的题目,只是参考了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 ?

浙公网安备 33010602011771号