• # Encore des problèmes de tests au borne

    Posté par . En réponse au message Advent of Code, jour 19. Évalué à 1.

    Je fatigue , il est temps que la saison se termine. J'ai encore perdu du temps sur des tests bête aux borne
    Environ ~3h00 au total.

    Encore obligé d'en arriver à écrire T.U. pour débuguer. Demain, je TDD, je vais probablement gagner du temps.

    Pour la partie 1, j'ai utilisé un evaluator JEXL pour les expressions.
    Pour la partie 2, je n'avais pas le choix. J'ai écris le "parseur" (En fait, c'est plutôt un split de l'expression) car il faut plus travailler sur des lots de pieces.

    Mon objet Piece a maintenant une propriété Range que je vais split à chaque expression en 0, 1 ou 2.

    Temps d'éxecution:123ms

    package aoc2023;
    import java.math.BigInteger;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Random;
    import java.util.Scanner;
    import java.util.Stack;
    import org.apache.commons.jexl3.JexlBuilder;
    import org.apache.commons.jexl3.JexlContext;
    import org.apache.commons.jexl3.JexlEngine;
    import org.apache.commons.jexl3.JexlExpression;
    import org.apache.commons.jexl3.MapContext;
    public class Aoc2023s19v2 {
     public static Random RANDOM = new Random(0L);
     public static JexlEngine jexl = new JexlBuilder().create();
     public static record Range(int start, int end) {
     public long count() {
     return end - start;
     }
     public Range[] split(int to) { 
     if(start >= to || to >= end) {
     return null;
     }
     return new Range[] { new Range(start, to), new Range(to, end) };
     }
     public Range random() {
     int i = start + RANDOM.nextInt((int)count());
     return new Range(i, i+1);
     }
     }
     public static class Piece {
     public Range x;
     public Range m;
     public Range a;
     public Range s;
     Piece(Range x, Range m, Range a, Range s) {
     this.x = x;
     this.m = m;
     this.a = a;
     this.s = s;
     }
     public long prod() {
     return x.count() * m.count() * a.count() * s.count();
     }
     @Override
     public String toString() {
     return "Piece [x=" + x + ", m=" + m + ", a=" + a + ", s=" + s + "]";
     }
     public Range get(String key) {
     return switch (key) {
     case "x" -> x;
     case "m" -> m;
     case "a" -> a;
     case "s" -> s;
     default -> throw new RuntimeException();
     };
     }
     public Piece substitute(String key, Range r) {
     return switch (key) {
     case "x" -> new Piece(r, m, a, s);
     case "m" -> new Piece(x, r, a, s);
     case "a" -> new Piece(x, m, r, s);
     case "s" -> new Piece(x, m, a, r);
     default -> throw new RuntimeException();
     };
     }
     }
     static class Rule {
     String condition;
     String destination;
     String attributTest;
     boolean attributeGreaterThan;
     int valueTest;
     Rule(String condition, String destination) {
     this.condition = condition;
     this.destination = destination;
     if(! this.condition.equals("true")) {
     attributTest = "" + this.condition.charAt(0);
     attributeGreaterThan = this.condition.charAt(1) == '>';
     valueTest = Integer.parseInt(this.condition.substring(2));
     }
     }
     public boolean match(Piece piece) {
     // Create a JEXL expression object
     JexlExpression jexlExpression = jexl.createExpression(condition);
     // Create a JexlContext and add the 'part' variable to it
     JexlContext context = new MapContext();
     context.set("x", piece.x.start);
     context.set("m", piece.m.start);
     context.set("s", piece.s.start);
     context.set("a", piece.a.start);
     // Evaluate the expression
     boolean result = (boolean) jexlExpression.evaluate(context);
     //System.out.println("Evaluation result: " + result);
     return result;
     }
     public String toString() {
     return condition + "," + destination;
     }
     public boolean process(Piece piece, Workflow workflow, Map<String, Workflow> workflows, List<Piece> accepts) {
     if(condition.equals("true")) {
     System.out.println("Default move to " + destination);
     getDestination(workflows, accepts).add(piece); 
     return true;
     }
     Range range = piece.get(attributTest); 
     System.out.println(this.condition);
     System.out.println(range);
     Range split[] = range.split(attributeGreaterThan ? valueTest +1: valueTest);
     if(split != null) {
     System.out.println("Splited to " + workflow.name + " & " + destination);
     System.out.println(split[0] + " <-> " + split[1]);
     if(attributeGreaterThan) {
     getDestination(workflows, accepts).add(piece.substitute(attributTest, split[1]));
     workflow.pieces.add(piece.substitute(attributTest, split[0]));
     } else {
     getDestination(workflows, accepts).add(piece.substitute(attributTest, split[0]));
     workflow.pieces.add(piece.substitute(attributTest, split[1])); 
     }
     return true;
     } else {
     if(attributeGreaterThan) {
     if(range.start > valueTest) { 
     System.out.println("Greater move to ");
     getDestination(workflows, accepts).add(piece.substitute(attributTest, range));
     return true;
     }
     } else {
     if((range.end-1) < valueTest) {
     System.out.println("Lower move to ");
     getDestination(workflows, accepts).add(piece.substitute(attributTest, range));
     return true;
     }
     }
     }
     return false;
     }
     private Collection<Piece> getDestination(Map<String, Workflow> workflows, List<Piece> accepts) { 
     if("A".equals(destination)) {
     return accepts;
     }
     if("R".equals(destination)) {
     return new ArrayList();
     }
     return workflows.get(destination).pieces;
     }
     }
     static class Workflow {
     String name;
     List<Rule> rules;
     Stack<Piece> pieces = new Stack();
     Workflow(String name) {
     this.name = name;
     this.rules = new ArrayList<>();
     }
     void addRule(Rule rule) {
     this.rules.add(rule);
     }
     public String toString() {
     StringBuilder sb = new StringBuilder();
     for (Rule rule : this.rules) {
     sb.append(rule.toString());
     }
     return sb.toString();
     }
     }
     static Map<String, Workflow> parseInput(Scanner in) {
     Map<String, Workflow> workflows = new HashMap<>();
     while (in.hasNext()) {
     String line = in.nextLine();
     line = line.trim();
     if (line.isEmpty()) {
     break;
     }
     String name = line.substring(0, line.indexOf('{')).trim();
     Workflow current = new Workflow(name);
     workflows.put(name, current);
     String[] parts = line.substring(line.indexOf('{') + 1, line.length() - 1).split(",");
     for (String part : parts) {
     String[] s = part.split(":");
     if (s.length == 1) {
     current.addRule(new Rule("true", s[0]));
     } else {
     current.addRule(new Rule(s[0], s[1]));
     }
     }
     }
     Range range = new Range(1, 4001);
     Piece base = new Piece(range, range, range, range);
     workflows.get("in").pieces.add(base);
     List<Piece> accepts = new ArrayList<>();
     computeAccepts(workflows, accepts);
     BigInteger sum = BigInteger.ZERO;
     for(Piece piece :accepts) {
     // uncomment to checkIndividual(piece, workflows);
     sum = sum.add(BigInteger.valueOf(piece.prod()));
     }
     System.out.println(sum);
     return workflows;
     }
     private static void checkIndividual(Piece rangePiece, Map<String, Workflow> workflows) { 
     for(int i=0;i < 1000;i++) {
     String currentName = "in";
     Piece piece = new Piece(
     rangePiece.x.random(),
     rangePiece.m.random(),
     rangePiece.a.random(),
     rangePiece.s.random()
     ); 
     //System.out.println("Piece:" + piece); 
     while(! currentName.equals("R") && !currentName.equals("A")) {
     //System.out.println("Current workflow:" + currentName);
     Workflow workflow = workflows.get(currentName);
     for(Rule rule : workflow.rules) {
     //System.out.println("Match:" + rule.condition);
     if(rule.match(piece)) {
     currentName = rule.destination; 
     //System.out.println("=>:" + rule.destination);
     break;
     }
     }
     }
     if(! currentName.equals("A")) {
     System.err.println(rangePiece);
     throw new RuntimeException(piece.toString());
     }
     }
     }
     private static void computeAccepts(Map<String, Workflow> workflows, List<Piece> accepts) {
     while (workflows.values().stream().filter(w -> !w.pieces.isEmpty()).count() > 0) {
     Workflow workflow = workflows.values().stream().filter(w -> !w.pieces.isEmpty()).findFirst().orElse(null);
     System.out.println("Workflow:" + workflow.name);
     Piece piece = workflow.pieces.pop();
     for (Rule rule : workflow.rules) {
     if (rule.process(piece, workflow, workflows, accepts)) {
     break;
     }
     }
     }
     }
     public static void main(String[] args) {
     long s = System.currentTimeMillis();
     try (Scanner in = new Scanner(Aoc2023s18v2.class.getResourceAsStream("res/t19.txt"))) {
     parseInput(in);
     }
     System.out.println("Durée:" + (System.currentTimeMillis() - s) + "ms");
     }
    }