Advertisement
Guest User

Untitled

a guest
Dec 26th, 2018
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.35 KB | None | 0 0
  1. package Advent2018;
  2.  
  3. import util.AdventOfCode;
  4. import util.FileIO;
  5.  
  6. import java.util.*;
  7. import java.util.concurrent.atomic.AtomicInteger;
  8. import java.util.regex.Matcher;
  9. import java.util.regex.Pattern;
  10. import java.util.stream.Collectors;
  11. import static java.util.Comparator.*;
  12.  
  13. public class Day24 extends AdventOfCode {
  14.  
  15.     List<Group> groups;
  16.     List<Group> original;
  17.  
  18.     enum AttackType {
  19.         COLD, FIRE, RADIATION, BLUDGEONING, SLASHING
  20.     }
  21.  
  22.     class Target {
  23.         int damage;
  24.         Group group;
  25.  
  26.         Target(Group group) {
  27.             //this.damage = damage;
  28.             this.group = group;
  29.         }
  30.         Target setDamage(int damage) {
  31.             this.damage = damage;
  32.             return this;
  33.         }
  34.         int getDamage() { return damage;}
  35.         int getPower() { return group.effectivePower(); }
  36.         int getInitiative() { return group.initiative; }
  37.     }
  38.  
  39.     class Group {
  40.         boolean immuneSystem;
  41.         boolean alive = true;
  42.         boolean chosen;
  43.         int units;
  44.         int hitPoints;
  45.         int attackDamage;
  46.         AttackType type;
  47.         int initiative;
  48.         List<AttackType> weak = new ArrayList<>();
  49.         List<AttackType> immune = new ArrayList<>();
  50.  
  51.         Group cloneGroup() {
  52.             Group g = new Group();
  53.             g.immuneSystem = this.immuneSystem;
  54.             g.units = this.units;
  55.             g.hitPoints = this.hitPoints;
  56.             g.attackDamage = attackDamage;
  57.             g.type = this.type;
  58.             g.initiative = this.initiative;
  59.             g.weak = this.weak;
  60.             g.immune = this.immune;
  61.             return g;
  62.         }
  63.  
  64.         int getInitiative() { return initiative; }
  65.  
  66.         int effectivePower() {
  67.             return units * attackDamage;
  68.         }
  69.  
  70.         boolean isWeakTo(Group other) {
  71.             return other.weak.contains(this.type);
  72.         }
  73.  
  74.         boolean isImmuneTo(Group other) {
  75.             return other.immune.contains(this.type);
  76.         }
  77.  
  78.         int damageVs(Group target) {
  79.             if (isImmuneTo(target)) return 0;
  80.             return effectivePower() + (isWeakTo(target) ? effectivePower() : 0);
  81.         }
  82.  
  83.         void takeDamage(int damage) {
  84.             units -= damage / hitPoints;
  85.             if (units <= 0) alive = false;
  86.         }
  87.  
  88.         @Override
  89.         public boolean equals(Object o) {
  90.             if (this == o) return true;
  91.             if (o == null || getClass() != o.getClass()) return false;
  92.  
  93.             Group group = (Group) o;
  94.  
  95.             if (immuneSystem != group.immuneSystem) return false;
  96.             if (alive != group.alive) return false;
  97.             if (chosen != group.chosen) return false;
  98.             if (units != group.units) return false;
  99.             if (hitPoints != group.hitPoints) return false;
  100.             if (attackDamage != group.attackDamage) return false;
  101.             if (initiative != group.initiative) return false;
  102.             if (type != group.type) return false;
  103.             if (weak != null ? !weak.equals(group.weak) : group.weak != null) return false;
  104.             return immune != null ? immune.equals(group.immune) : group.immune == null;
  105.         }
  106.  
  107.         @Override
  108.         public int hashCode() {
  109.             int result = (immuneSystem ? 1 : 0);
  110.             result = 31 * result + (alive ? 1 : 0);
  111.             result = 31 * result + (chosen ? 1 : 0);
  112.             result = 31 * result + units;
  113.             result = 31 * result + hitPoints;
  114.             result = 31 * result + attackDamage;
  115.             result = 31 * result + (type != null ? type.hashCode() : 0);
  116.             result = 31 * result + initiative;
  117.             result = 31 * result + (weak != null ? weak.hashCode() : 0);
  118.             result = 31 * result + (immune != null ? immune.hashCode() : 0);
  119.             return result;
  120.         }
  121.  
  122.         @Override
  123.         public String toString() {
  124.             return "Group " + initiative + "{" +
  125.                     "immuneSystem=" + immuneSystem +
  126.                     ", units=" + units +
  127.                     ", hitPoints=" + hitPoints +
  128.                     '}';
  129.         }
  130.     }
  131.  
  132.     void resetGroups() {
  133.         groups = new ArrayList<>();
  134.         for (int i = 0; i < original.size(); i++) {
  135.             groups.add(original.get(i).cloneGroup());
  136.         }
  137.     }
  138.  
  139.  
  140.  
  141.     public Day24(List<String> input) {
  142.         super(input);
  143.     }
  144.  
  145.  
  146.     void fight() {
  147.  
  148.         // target selection
  149.         groups.forEach(x -> x.chosen = false);
  150.         Map<Group, Target> opponents = new HashMap<>();
  151.         List<Group> avail = groups.stream()
  152.                 .filter(x -> x.alive)
  153.                 .sorted(comparing(Group::effectivePower)
  154.                         .thenComparing(Group::getInitiative)
  155.                         .reversed())
  156.                 .collect(Collectors.toList());
  157.  
  158.         for (Group each : avail) {
  159.  
  160.             List<Target> targets = avail.stream()
  161.                     .filter(x -> x.immuneSystem != each.immuneSystem)
  162.                     .filter(x -> !x.chosen)
  163.                     .filter(x -> !each.isImmuneTo(x))
  164.                     .map(Target::new)
  165.                     .map(x -> x.setDamage(each.damageVs(x.group)))
  166.                     .sorted(comparing(Target::getDamage)
  167.                             .thenComparing(Target::getPower)
  168.                             .thenComparing(Target::getInitiative)
  169.                             .reversed())
  170.                     .collect(Collectors.toList());
  171.            
  172.  
  173.             if (targets.size() > 0) {
  174.                 Target t = targets.get(0);
  175.                 opponents.put(each, t);
  176.                 t.group.chosen = true;
  177.             }
  178.         }
  179.  
  180.         // attack phase
  181.         opponents.entrySet().stream()
  182.                 .sorted(Map.Entry.comparingByKey(comparing(Group::getInitiative).reversed()))
  183.                 .forEach(x -> {
  184.                     //System.out.println(x.getKey() + " attacks");
  185.                     //System.out.println(x.getValue().group);
  186.                     x.getValue().group.takeDamage(x.getKey().damageVs(x.getValue().group));
  187.                     //System.out.println(x.getValue().group);
  188.                 });
  189.         //System.out.println("end fight");
  190.     }
  191.  
  192.     boolean fightOver() {
  193.         return groups.stream().filter(x -> x.immuneSystem && x.alive).count() == 0 ||
  194.                 groups.stream().filter(x -> !x.immuneSystem && x.alive).count() == 0;
  195.     }
  196.  
  197.     @Override
  198.     public Object part1() {
  199.         resetGroups();
  200.         while (!fightOver()) {
  201.             fight();
  202.  
  203.         }
  204.         return groups.stream().filter(x -> x.alive).mapToInt(x -> x.units).sum() - 1;
  205.     }
  206.  
  207.     @Override
  208.     public Object part2() {
  209.         AtomicInteger boost = new AtomicInteger(52);
  210.         int immuneScore = 0;
  211.         while (immuneScore == 0) {
  212.             resetGroups();
  213.             groups.stream().filter(x -> x.immuneSystem).forEach(x -> x.attackDamage += boost.get());
  214.             while (!fightOver()) {
  215.                 fight();
  216.             }
  217.             boost.incrementAndGet();
  218.             immuneScore = groups.stream()
  219.                     .filter(x -> x.immuneSystem)
  220.                     .filter(x -> x.alive)
  221.                     .mapToInt(x -> x.units).sum();
  222.         }
  223.  
  224.         return immuneScore;
  225.     }
  226.  
  227.     @Override
  228.     public void parse() {
  229.         //input = FileIO.getFileAsList("puzzle_input/test24.txt");
  230.         original = new ArrayList<>();
  231.         Pattern p = Pattern.compile("(\\d+) units each with (\\d+) hit points \\(?.*\\)? ?with an attack that does (\\d+) (\\w+) damage at initiative (\\d+)");
  232.         boolean immune = true;
  233.         for (String line : input) {
  234.             if (line.equals("Immune System:")) continue;
  235.             if (line.isEmpty()) continue;
  236.             if (line.equals("Infection:")) {
  237.                 immune = false;
  238.                 continue;
  239.             }
  240.             Group g = new Group();
  241.             Matcher m = p.matcher(line);
  242.             if (m.find()) {
  243.                 g.immuneSystem = immune;
  244.                 g.units = Integer.parseInt(m.group(1));
  245.                 g.hitPoints = Integer.parseInt(m.group(2));
  246.                 g.attackDamage = Integer.parseInt(m.group(3));
  247.                 g.type = AttackType.valueOf(m.group(4).toUpperCase());
  248.                 g.initiative = Integer.parseInt(m.group(5));
  249.             }
  250.             if (line.contains("(")) {
  251.                 String[] special = line.substring(line.indexOf('(') + 1, line.lastIndexOf(')')).split("; ");
  252.                 if (special.length > 0) {
  253.                     for (String each : special) {
  254.                         each = each.replaceAll(",", "");
  255.                         String[] split = each.split(" ");
  256.                         if (split[0].equals("immune")) {
  257.                             for (int i = 2; i < split.length; i++) {
  258.                                 g.immune.add(AttackType.valueOf(split[i].toUpperCase()));
  259.                             }
  260.                         } else {
  261.                             if (split[0].equals("weak")) {
  262.                                 for (int i = 2; i < split.length; i++) {
  263.                                     g.weak.add(AttackType.valueOf(split[i].toUpperCase()));
  264.                                 }
  265.                             }
  266.                         }
  267.                     }
  268.                 }
  269.             }
  270.  
  271.             original.add(g);
  272.  
  273.         }
  274.     }
  275.  
  276. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement