Advent of Code 2021

I finished day 25, and thus the whole AoC 2021. The last day is a sort of modified game of life simulation. It’s not really very tricky, except that you do need to process each round in two stages.

Here’s my SeaCucumberSimulation class:

final class SeaCucumberSimulation
{
  private final int width;
  private final int height;
  private char[][] seaCucumbers;
  
  public SeaCucumberSimulation(final String[] initialConfiguration)
  {
    width = initialConfiguration[0].length();
    height = initialConfiguration.length;
    // System.out.format("Width=%d Height=%d%n", width, height);
    seaCucumbers = new char[width][height];
    
    for (int y=0; y<height; y++)
    {
      for (int x=0; x<width; x++)
      {
        seaCucumbers[x][y] = initialConfiguration[y].charAt(x);
      }
    }
  }

  public long runUntilNoneMove()
  {
    int numberRounds = 1;
    boolean someMoved = true;
    while (someMoved)
    {
      someMoved = oneRound();
      if (someMoved)
      {
        numberRounds++;
      // System.out.println("after round " + numberRounds);
      // outputOceanFloor();
      }
    }

    return numberRounds;
  }

  boolean oneRound()
  {
    char[][] newSeaCucumbers = new char[width][height];
    boolean someMoved = false;
    
    for (int y=0; y<height; y++)
    {
      for (int x=0; x<width; x++)
      {
        newSeaCucumbers[x][y] = '.'; 
      }
    }

    for (int y=0; y<height; y++)
    {
      for (int x=0; x<width; x++)
      {
        final int nextX;
        if (x == width-1)
          nextX=0;
        else
          nextX=x+1;
        if (seaCucumbers[x][y] == 'v')
          newSeaCucumbers[x][y] = 'v';

        if (seaCucumbers[x][y] == '>')
        {
          if (seaCucumbers[nextX][y] == '.')
          {
            someMoved = true;
            newSeaCucumbers[nextX][y] = '>';
          }
          else
          {
            newSeaCucumbers[x][y]   = '>'; 
          }
        }
      }
    }

    seaCucumbers = newSeaCucumbers;
    newSeaCucumbers = new char[width][height];
    for (int y=0; y<height; y++)
    {
      for (int x=0; x<width; x++)
      {
        newSeaCucumbers[x][y] = '.'; 
      }
    }

    boolean someMoved2 = false;
    for (int x=0; x<width; x++)
    {
      for (int y=0; y<height; y++)
      {
        final int nextY;
        if (y == height-1)
          nextY=0;
        else
          nextY=y+1;

        if (seaCucumbers[x][y] == '>')
          newSeaCucumbers[x][y] = '>';

        if (seaCucumbers[x][y] == 'v')
        {
          if (seaCucumbers[x][nextY] == '.')
          {
            someMoved2 = true;
            newSeaCucumbers[x][nextY] = 'v'; 
          }
          else
          {
            newSeaCucumbers[x][y]   = 'v'; 
          }
        }
      }
    }

    seaCucumbers = newSeaCucumbers;

    return someMoved || someMoved2;
  }

  void outputOceanFloor()
  {
    System.out.println(this.toString());
  }

  @Override
  public String toString()
  {
    final StringBuilder sb = new StringBuilder();
    for (int y=0; y<height; y++)
    {
      for (int x=0; x<width; x++)
      {
        sb.append(seaCucumbers[x][y]);
      }
      sb.append('\n');
    }
    return sb.toString();
  }
}

Which then gets exercised by

public static long getPart1Answer(final String day25Input, final String[] day25InputLines)
{
  final SeaCucumberSimulation scs = new SeaCucumberSimulation(day25InputLines);
  return scs.runUntilNoneMove();
}

As appears to be the tradition, there is no part two for day 25… it’s just a matter of having all 49 stars to that point to complete it.

Totally enjoying it. I’m learning all sorts of useful stuff. It boggles the mind how you whip through these. I hope by the time I’m 80 I can do the same! I was feeling pretty cocky up until I got stuck.

I am frozen on Day 9 Part 2 because I can’t get Racket to bend to my will. I’m using a flood-fill algorithm which I know will work, but I’ve got something wrong in the syntax. The recursion never terminates and the seen list doesn’t populate. It’s something dumb I know, but, so far, I am reluctant to seek help.

;; Natural Grid -> Natural
;; Given a low point in a grid, return the number of points in the basin
;; (including low-point)
(define (get-basin p g)
  "uses flood-fill algorithm to count the points in a basin"
  (local [(define seen empty)
          (define width (grid-width g))
 
          (define (inside-grid? x) (< -1 x (vector-length (grid-points g))))
          (define (inside-basin? x) (not (equal? 9 (get-value x g))))

          (define (flood pt)
            "recurse through basin until we've hit the borders"
            (when (and (inside-grid? pt)      
                       (inside-basin? pt)     
                       (not (member pt seen))) 
              (cons pt seen)                   ; accumulate point list
              (flood (add1 pt))                ; expand right
              (flood (sub1 pt))                ; expand left
              (flood  (+ pt width))            ; expand down
              (flood (- pt width))))]          ; expand up
    (flood p)))

(Not a spoiler because the damn thing doesn’t work!)

Oh, and Merry Christmas! Thanks for all your help in here. I really really appreciate it.

1 Like

Hah. It was such a stupid mistake. I finally asked in the Racket Discord and got a quick answer. I will write 100 times: lists in Racket are not mutable. D’oh! As soon as I fixed that my solution worked.

On to Day 10! :smiley_cat:

1 Like

Shouldn’t the system give you this hint in some way when you try to do it? Like an exception or something?

cons returns a new list, so it’s a valid thing to do. It would take more effort than catching an illegal action for the language tooling to say, “hmm, you’re not saving that value anywhere, maybe you thought you could mutate the list…”.

Yeah it would have been nice, but now I’m on to glowing octupi.

Boy Day 10 was a cinch. Day 11 is just a game of life - nothing to tricky in part 1 anyway. Still having fun!