Advent of Code, day 15

This December I participated in Advent of Code.

I don’t remember part 1 being hard. Tedious, but not hard. All that “if this goes left, then…” I might have to code a general “if I am facing left, and looking to my right…” routine some day.

Part 2 on the other hand… Figuring out the correct recursion when going up or down. If I am trying to move up, but there’s a box partially above me, I have to move that first. Only after it’s moved, can I move. This took endless debugging, and trying to get the test case to work correctly.

I am on my way to always having the functions at the top of the code.

Part 1:

<?php

// map in
function print_map() {
  global $map, $mapwid, $maphei;
  for($j=0;$j<$maphei;$j++) {
    for($i=0;$i<$mapwid;$i++) {
      if(isset($map[$j][$j])) {
        echo $map[$j][$i];
      } else {
        echo ".";
      }
    }
    echo "\n";
  }
  echo "\n";
}

$input = file_get_contents('./d15input2.txt', true);

$map = array();
$phase = 1;
foreach(preg_split("/((\r?\n)|(\r\n?))/", $input) as $line) {
  if(strlen($line) < 3) {
    $phase = 2;
  } else {
    if($phase == 1) {
      $map[] = str_split($line);
    } else {
      $moves[] = str_split($line);
    }
  }
}
$maphei = sizeof($map);
$mapwid = sizeof($map[0]);
$moves = array_merge(...$moves);

// find robot
// find guard
for($i=0;$i<$maphei;$i++) {
  $j = array_search("@", $map[$i]);
  if($j) {
    $robx = $j;
    $roby = $i;
  }
}
print_map();

function movebox($x, $y, $dir) {
  global $map;
  switch ($dir) {
    case "<":
      if($map[$y][$x-1] == "#") {
        return 0;
      }
      if($map[$y][$x-1] == "O") {
        $tmp = movebox($x-1, $y, $dir);
        if($tmp == 1) {
          $map[$y][$x-2] = "O";
          $map[$y][$x-1] = ".";
        }
        return $tmp;
      } else {
        return 1;
      }
      break;
    case "v":
      if($map[$y+1][$x] == "#") {
        return 0;
      }
      if($map[$y+1][$x] == "O") {
        $tmp = movebox($x, $y+1, $dir);
        if($tmp == 1) {
          $map[$y+2][$x] = "O";
          $map[$y+1][$x] = ".";
        }
        return $tmp;
      } else {
        return 1;
      }
      break;
    case ">":
      if($map[$y][$x+1] == "#") {
        return 0;
      }
      if($map[$y][$x+1] == "O") {
        $tmp = movebox($x+1, $y, $dir);
        if($tmp == 1) {
          $map[$y][$x+2] = "O";
          $map[$y][$x+1] = ".";
        }
        return $tmp;
      } else {
        return 1;
      }
      break;
    case "^":
      if($map[$y-1][$x] == "#") {
        return 0;
      }
      if($map[$y-1][$x] == "O") {
        $tmp = movebox($x, $y-1, $dir);
        if($tmp == 1) {
          $map[$y-2][$x] = "O";
          $map[$y-1][$x] = ".";
        }
        return $tmp;
      } else {
        return 1;
      }
      break;
  }
}

// walk the robot
for($i=0;$i<sizeof($moves);$i++) {
  if(movebox($robx, $roby, $moves[$i])) {
    if($moves[$i] == "^") {
      if($map[$roby-1][$robx] != "#") {
        $map[$roby-1][$robx] = "@";
        $map[$roby][$robx] = ".";
        $roby--;
      }
    }
    if($moves[$i] == ">") {
      if($map[$roby][$robx+1] != "#") {
        $map[$roby][$robx+1] = "@";
        $map[$roby][$robx] = ".";
        $robx++;
      }
    }
    if($moves[$i] == "v") {
      if($map[$roby+1][$robx] != "#") {
        $map[$roby+1][$robx] = "@";
        $map[$roby][$robx] = ".";
        $roby++;
      }
    }
    if($moves[$i] == "<") {
      if($map[$roby][$robx-1] != "#") {
        $map[$roby][$robx-1] = "@";
        $map[$roby][$robx] = ".";
        $robx--;
      }
    }
  }
}

print_map();

// calculate gps
$gps = 0;
for($j=0;$j<$maphei;$j++) {
  for($i=0;$i<$mapwid;$i++) {
    if($map[$j][$i] == "O") {
      $gps += 100 * $j + $i;
    }
  }
}
echo "$gps\n";

?>

Part 2:

<?php
// map in
function print_map() {
  global $map, $mapwid, $maphei;
  for($j=0;$j<$maphei;$j++) {
    for($i=0;$i<$mapwid;$i++) {
      if(isset($map[$j][$j])) {
        echo $map[$j][$i];
      } else {
        echo ".";
      }
    }
    echo "\n";
  }
  echo "\n";
}


$input = file_get_contents('./d15input2.txt', true);

$map = array();
$phase = 1;
foreach(preg_split("/((\r?\n)|(\r\n?))/", $input) as $line) {
  if(strlen($line) < 3) {
    $phase = 2;
  } else {
    if($phase == 1) {
      $map[] = str_split($line);
    } else {
      $moves[] = str_split($line);
    }
  }
}

// make map twice the width
foreach($map as $row) {
  foreach($row as $cell) {
    switch($cell) {
      case "#":
        $r2[] = $cell;
        $r2[] = $cell;
        break;
      case "@":
        $r2[] = $cell;
        $r2[] = ".";
        break;
      case "O":
        $r2[] = "[";
        $r2[] = "]";
        break;
      case ".":
        $r2[] = $cell;
        $r2[] = $cell;
        break;
    }
  }
  $m2[] = $r2;
  $r2 = array();
}
$map = $m2;

$maphei = sizeof($map);
$mapwid = sizeof($map[0]);
$moves = array_merge(...$moves);

// find robot
for($i=0;$i<$maphei;$i++) {
  $j = array_search("@", $map[$i]);
  if($j) {
    //print("$i $j");
    $robx = $j;
    $roby = $i;
  }
}
print_map();

function moveboxupdown($x, $y, $dir, $mywid) {

  global $map;
  // i am on (x,y) and i am mywid wide, going in dir direction
  // if there is a box in front of me, move it, if possible
  // note, adjacent boxes may be moved partially and then rolled back
  // if i am a box, (x,y) is my left part
  
  // first, check for wall
  if($dir == "^" && $map[$y-1][$x] == "#") {
    // wall, abort
    return 0;
  }
  if($dir == "^" && $mywid == 2 && $map[$y-1][$x+1] == "#") {
    // wall, abort
    return 0;
  }
  if($dir == "v" && $map[$y+1][$x] == "#") {
    // wall, abort
    return 0;
  }
  if($dir == "v" && $mywid == 2 && $map[$y+1][$x+1] == "#") {
    // wall, abort
    return 0;
  }

  // next check for further boxes, and move them!
  if($dir == "^" && $map[$y-1][$x-1] == "[") {
    $tmp = moveboxupdown($x-1, $y-1, $dir, 2);
    if($tmp == 0) {
      return 0;
    }
  }
  if($dir == "^" && $map[$y-1][$x] == "[") {
    $tmp = moveboxupdown($x, $y-1, $dir, 2);
    if($tmp == 0) {
      return 0;
    }
  }
  if($dir == "^" && $mywid == 2 && $map[$y-1][$x+1] == "[") {
    $tmp = moveboxupdown($x+1, $y-1, $dir, 2);
    if($tmp == 0) {
      return 0;
    }
  }
  if($dir == "v" && $map[$y+1][$x-1] == "[") {
    $tmp = moveboxupdown($x-1, $y+1, $dir, 2);
    if($tmp == 0) {
      return 0;
    }
  }
  if($dir == "v" && $map[$y+1][$x] == "[") {
    $tmp = moveboxupdown($x, $y+1, $dir, 2);
    if($tmp == 0) {
      return 0;
    }
  }
  if($dir == "v" && $mywid == 2 && $map[$y+1][$x+1] == "[") {
    $tmp = moveboxupdown($x+1, $y+1, $dir, 2);
    if($tmp == 0) {
      return 0;
    }
  }
  
  // if i reached this point, i can move a box
  if($dir == "^" && $mywid == 2) {
    $map[$y-1][$x] = "[";
    $map[$y-1][$x+1] = "]";
    $map[$y][$x] = ".";
    $map[$y][$x+1] = ".";
  }
  if($dir == "v" && $mywid == 2) {
    $map[$y+1][$x] = "[";
    $map[$y+1][$x+1] = "]";
    $map[$y][$x] = ".";
    $map[$y][$x+1] = ".";
  }

  return 1;
}

function moveboxleftright($x, $y, $dir) {
  global $map;
  switch ($dir) {
    case "<":
      if($map[$y][$x-1] == "#") {
        return 0;
      }
      if($map[$y][$x-1] == "]") {
        $tmp = moveboxleftright($x-2, $y, $dir);
        if($tmp == 1) {
          $map[$y][$x-3] = "[";
          $map[$y][$x-2] = "]";
          $map[$y][$x-1] = ".";
        }
        return $tmp;
      } else {
        return 1;
      }
      break;
    case ">":
      if($map[$y][$x+1] == "#") {
        return 0;
      }
      if($map[$y][$x+1] == "[") {
        $tmp = movebox($x+2, $y, $dir);
        if($tmp == 1) {
          $map[$y][$x+3] = "]";
          $map[$y][$x+2] = "[";
          $map[$y][$x+1] = ".";
        }
        return $tmp;
      } else {
        return 1;
      }
      break;
  }
}

function movebox($x, $y, $dir) {
  global $map;
  $backup = $map;
  if($dir == "^" || $dir == "v") {
    $tmp = moveboxupdown($x, $y, $dir, 1);
  } else {
    $tmp = moveboxleftright($x, $y, $dir);
  }
  if($tmp == 0) {
    $map = $backup;
  }
  return $tmp;
}

// walk the robot
for($i=0;$i<sizeof($moves);$i++) {
  if(movebox($robx, $roby, $moves[$i])) {
    if($moves[$i] == "^") {
      if($map[$roby-1][$robx] != "#") {
        $map[$roby-1][$robx] = "@";
        $map[$roby][$robx] = ".";
        $roby--;
      }
    }
    if($moves[$i] == ">") {
      if($map[$roby][$robx+1] != "#") {
        $map[$roby][$robx+1] = "@";
        $map[$roby][$robx] = ".";
        $robx++;
      }
    }
    if($moves[$i] == "v") {
      if($map[$roby+1][$robx] != "#") {
        $map[$roby+1][$robx] = "@";
        $map[$roby][$robx] = ".";
        $roby++;
      }
    }
    if($moves[$i] == "<") {
      if($map[$roby][$robx-1] != "#") {
        $map[$roby][$robx-1] = "@";
        $map[$roby][$robx] = ".";
        $robx--;
      }
    }
  }
}

print_map();

// calculate gps
$gps = 0;
for($j=0;$j<$maphei;$j++) {
  for($i=0;$i<$mapwid;$i++) {
    if($map[$j][$i] == "[") {
      $gps += 100 * $j + $i;
    }
  }
}
echo "$gps\n";
?>

Skriv en kommentar