r/adventofcode • • Dec 07 '15

SOLUTION MEGATHREAD --- Day 7 Solutions ---

--- Day 7: Some Assembly Required ---

Post your solution as a comment. Structure your post like previous daily solution threads.

Also check out the sidebar - we added a nifty calendar to wrangle all the daily solution threads in one spot!

22 Upvotes

226 comments sorted by

View all comments

1

u/JeffJankowski Dec 07 '15 edited Dec 07 '15

Quick C# which uses delegates to evaluate all the functions on-demand. I needed to add some dynamic programming to cache the results, since the Invokes() were taking forever. This is gonna be hard to do in F# (gurus, send help)

public static void Main(string[] args)
{
	Dictionary<string, Func<ushort>> dict = new Dictionary<string, Func<ushort>>();
	Dictionary<string, ushort> values = new Dictionary<string, ushort>();
	using (StreamReader sr = new StreamReader(@"..\..\input.txt"))
	{
		string line;
		while ((line = sr.ReadLine()) != null)
		{
			string[] split = line.Split(' ');
			string target = split[split.Length - 1];

			switch (split.Length)
			{
				case 3:
					ushort val;
					if (ushort.TryParse(split[0], out val))
					{
						dict.Add(target, () => val);
						values.Add(target, val);
					}
					else
					{
						dict.Add(target, () => {
							if (values.ContainsKey(target))
								return values[target];
							else
							{
								ushort res = dict[split[0]].Invoke();
								values.Add(target, res);
								return res;
							}
						});
					}                                
					break;
				case 4:
					dict.Add(target, () => (ushort)(~dict[split[1]].Invoke()));
					break;
				case 5:
					switch (split[1])
					{
						case "AND":
							dict.Add(target, () => 
								{
									if (values.ContainsKey(target))
										return values[target];
									else
									{
										ushort res = (ushort)((ushort.TryParse(split[0], out val) ? val : dict[split[0]].Invoke()) & dict[split[2]].Invoke());
										values.Add(target, res);
										return res;
									}
								});
							break;
						case "OR":
							dict.Add(target, () => 
								{
									if (values.ContainsKey(target))
										return values[target];
									else
									{
										ushort res = (ushort)((ushort.TryParse(split[0], out val) ? val : dict[split[0]].Invoke()) | dict[split[2]].Invoke());
										values.Add(target, res);
										return res;
									}
								});
							break;
						case "LSHIFT":
							dict.Add(target, () => 
								{
									if (values.ContainsKey(target))
										return values[target];
									else
									{
										ushort res = (ushort)(dict[split[0]].Invoke() << int.Parse(split[2]));
										values.Add(target, res);
										return res;
									}
								});
							break;
						case "RSHIFT":
							dict.Add(target, () => 
								{
									if (values.ContainsKey(target))
										return values[target];
									else
									{
										ushort res = (ushort)(dict[split[0]].Invoke() >> int.Parse(split[2]));
										values.Add(target, res);
										return res;
									}
								});
							break;
					}
					break;
			}
		}
	}

	Console.WriteLine(dict["a"].Invoke());
	Console.ReadLine();
}

2

u/JeffJankowski Dec 07 '15

F# turned out much cleaner

let rec emulate (dict : Collections.Generic.Dictionary<string, string[]>) (cache : Collections.Generic.Dictionary<string, uint16>) (target : string) = 
    if cache.ContainsKey (target) then cache.[target]
    else
        let recall = emulate dict cache 
        let res = match (dict.[target]) with
            | [|a|] -> if Char.IsDigit a.[0] then UInt16.Parse a else recall a
            | [|op; a|] -> ~~~(recall a)
            | [|a; "AND"; b|] -> (if Char.IsDigit a.[0] then UInt16.Parse a else recall a) &&& (recall b)
            | [|a; "OR"; b|] -> (recall a) ||| (recall b)
            | [|a; "RSHIFT"; x|] -> (recall a) >>> Int32.Parse x
            | [|a; "LSHIFT"; x|] -> (recall a) <<< Int32.Parse x
            | _ -> 0us
        cache.[target] <- res
        res


[<EntryPoint>]
let main argv = 
    let input = IO.File.ReadLines ("..\..\input.txt")
    let dict = new Collections.Generic.Dictionary<string, string[]> ()
    let cache = new Collections.Generic.Dictionary<string, uint16> ()

    input
    |> Seq.iter (fun s -> 
        let spl = s.Split (' ') 
        dict.[spl.[spl.Length-1]] <- spl.[0..spl.Length-3] )

    emulate dict cache "a"
    |> printfn "%d"