Advent of Code Day 12 (C#)

Advent of Code 2016 Day 11 (Groovy)
Advent of Code 2016 Day 10 (OcaML)

Advent of Code 2016 Day 9 (Factor)

Advent of Code 2016 Day 8 (c++)
Advent of Code 2016 Day 7 (Javascript)
Advent of Code 2016 – Day 6 (Julia)
Advent of Code 2016 – Day 5( Java 8)

Advent of Code 2016 – Day 4 (Perl 6)

Advent of Code 2016 – Day 3 (Clojure)
Advent of Code – Day 2 (Python 3)
Advent Of Code 2016 – Day 1(Haskell)

Day 12

Start: 12/18/2016

Finish 12/18/2016

Language: C#

SPOILER ALERT: If you have any inkling, any whatsoever, to work on the Advent of Code…. DO NOT READ THIS BLOG POST.  DO NOT LOOK AT MY GITHUB PROJECT.  It is no fun if you’re not solving it yourself, and you’ll feel so much better about yourself if you can figure it out without looking up an answer.  This blog post is not to give away the answer, but instead, is there for people to learn from.

As always, the following code is in my GitHub: https://github.com/pviafore/AdventOfCode2016

The Challenge

This was a welcome change after quite a few messy problems.  I finished this one in under two hours, and it made me feel good as well.  This challenge was about decoding a simple assembly language (made up of COPY, INC, DEC and JNZ commands).

I knew what I wanted to do right away.  I wanted to treat the registers as variables, and each instruction as a function.  All I had to do was map the instructions to closures that contained the instructions I wanted, and I’d be all set.

 

 

Part 1

The code isn’t too verbose, so I’ll start with it:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

public class Challenge1
{
    int a = 0;
    int b = 0;
    int c = 0;
    int d = 0;
    int instructionPointer = 0;

    private int read(String value)
    {
        if(value == "a") return a;
        if(value == "b") return b;
        if(value == "c") return c;
        if(value == "d") return d;
        return Int32.Parse(value);
    }

    private void write(String address, int value)
    {
        if(address == "a") a = value;
        if(address == "b") b = value;
        if(address == "c") c = value;
        if(address == "d") d = value;
    }

    private Action getCpy(string instruction)
    {
        string pattern = @"cpy (\w+) (\w+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            write(m.Groups[2].ToString(), read(m.Groups[1].ToString()));
            instructionPointer++;
        };
    }

    private Action getInc(string instruction)
    {
        string pattern = @"inc (\w+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            write(m.Groups[1].ToString(), read(m.Groups[1].ToString())+1);
            instructionPointer++;
        };
    }

    private Action getDec(string instruction)
    {
        string pattern = @"dec (\w+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            write(m.Groups[1].ToString(), read(m.Groups[1].ToString())-1);
            instructionPointer ++;
        };
    }

    private Action getJnz(string instruction)
    {
        string pattern = @"jnz (\w+) ([-|\w]+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            if (read(m.Groups[1].ToString()) != 0)
            {
                instructionPointer = instructionPointer + read(m.Groups[2].ToString());
            }
            else
            {
                instructionPointer++;
            }
        };
    }
    
    private  string[] readFile()
    {
        return System.IO.File.ReadAllLines("../day12.txt");
    }

    private Action getInstruction(string instruction)
    {
        instruction = instruction.Trim();
        if (instruction.StartsWith("cpy")) return getCpy(instruction);
        if (instruction.StartsWith("inc")) return getInc(instruction);
        if (instruction.StartsWith("dec")) return getDec(instruction);
        else return getJnz(instruction);
    }

    private void solve()
    {
        string[] lines = readFile();
        IEnumerable instructions = lines.Select(i => getInstruction(i));
        while(instructionPointer < instructions.Count())
        {
            instructions.ElementAt(instructionPointer)();
        }
        System.Console.WriteLine("A is: " + a);

        
    }
    static public void Main ()
    {
        Challenge1 challenge1 = new Challenge1();
        challenge1.solve();        
    }
}

 

There’s two main parts to the code, the mapping of strings into insructions, and the closures themselves.

First, let’s look how how we decide which instruction is what.  We read each line as a string and then map it into an instruction.  Instructions return an Action (which is just a closure that takes no arguments and has no return value (It reminds me of the Command pattern).  We look at the first letters in an instruction to select which function to call:


 private Action getInstruction(string instruction)
    {
        instruction = instruction.Trim();
        if (instruction.StartsWith("cpy")) return getCpy(instruction);
        if (instruction.StartsWith("inc")) return getInc(instruction);
        if (instruction.StartsWith("dec")) return getDec(instruction);
        else return getJnz(instruction);
    }

    private void solve()
    {
        string[] lines = readFile();
        IEnumerable instructions = lines.Select(i => getInstruction(i));
        while(instructionPointer < instructions.Count())
        {
            instructions.ElementAt(instructionPointer)();
        }
        System.Console.WriteLine("A is: " + a);

        
    }

Then inside each function, we parse the command and return a closure that operates on the values we set in the class (a,b,c,d, and an instruction pointer).


 private Action getCpy(string instruction)
    {
        string pattern = @"cpy (\w+) (\w+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            write(m.Groups[2].ToString(), read(m.Groups[1].ToString()));
            instructionPointer++;
        };
    }

    private Action getInc(string instruction)
    {
        string pattern = @"inc (\w+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            write(m.Groups[1].ToString(), read(m.Groups[1].ToString())+1);
            instructionPointer++;
        };
    }

    private Action getDec(string instruction)
    {
        string pattern = @"dec (\w+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            write(m.Groups[1].ToString(), read(m.Groups[1].ToString())-1);
            instructionPointer ++;
        };
    }

    private Action getJnz(string instruction)
    {
        string pattern = @"jnz (\w+) ([-|\w]+)";
        Match  m = Regex.Match(instruction, pattern);
        return () => {
            if (read(m.Groups[1].ToString()) != 0)
            {
                instructionPointer = instructionPointer + read(m.Groups[2].ToString());
            }
            else
            {
                instructionPointer++;
            }
        };
    }
   

I had a few mess-ups with my regular expressions handling negative numbers in JNZ commands, but once I had that, it worked like a charm.

Part 2

All I had to do is change one byte to get part 2 to work -> Initialize C to 1.  It took a little while to run, but it finished, and I got the right answer.

Wrap-up

This one went great.  I solved it quickly in a new language.  I finally got to try out a .NET language, and played around with LINQ (albeit for one call).  Still, it was nice to see a quick solution after three or four challenges of struggles.

I give my grade for this one an A.  It didn’t run fast, but I liked the use of closures and during my research I saw the potential for LINQ.

I think I’ll try out Lua next for day 13.

 

9 thoughts on “Advent of Code Day 12 (C#)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s