syj a écrit 650 commentaires

  • # 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");
        }
    }
  • # Bof , bof, je n'ai pas vraiment trouvé par moi-même.

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

    Pour la première partie, j'ai utilisé un bête algo de remplissage de forme par propagation.

    Pour la deuxième partie, je connaissais l'algorithme du lacets(Shoelace) pour en avoir entendu parlé récemment.
    Je me doutais qu'il fallait retirer le périmètre du polygone.

    Par contre, je ne trouvais pas malgré toutes mes investigations ,c'est en lisant le CR de Guillaume que j'ai découvert le théorème de Pick et son usage.

    Mon implémtentation en Java.

    package aoc2023;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    
    public class Aoc2023s18v2 {
        public static record Point(long x, long y) {
            public Point createRelative(Point dir, long factor) {
                return new Point(x + dir.x * factor, y + dir.y * factor);
            }
    
            public double dist(Point p) {
                long dx = p.x - x;
                long dy = p.y - y;
    
                return Math.sqrt(dx * dx + dy * dy);
            }
        }
    
        public static List<String> ORDERS = Arrays.asList("R", "D", "L", "U");
    
        public static Map<String, Point> DIRECTIONS = Map.of("U", new Point(0, -1), "R", new Point(1, 0), "D",
                new Point(0, 1), "L", new Point(-1, 0));
    
        public static Map<String, String> DIRECTIONS_TRAD = Map.of("3", "U", "0", "R", "1", "D", "2", "L");
    
        public static long calculateArea2(List<Point> listPoints) {
            Point[] points = listPoints.toArray(new Point[listPoints.size()]);
            double sum = 0.0;
    
            for (int i = 0; i < points.length - 1; ++i) {
                sum += (points[i].x * points[i + 1].y) - (points[i + 1].x * points[i].y);
            }
            long perimeter = dist(listPoints);
            long s1 = (long) (Math.abs(sum) - perimeter);
            s1 = s1 / 2;
            s1 += 1;
            return s1 + perimeter;
        }
    
        public static long dist(List<Point> poly) {
            double sum = 0;
            for (int x = 1; x < (poly.size()); x++) {
                sum += poly.get(x - 1).dist(poly.get(x));
            }
    
            sum += poly.get(poly.size() - 1).dist(poly.get(0));
            return (long) sum;
        }
    
        public static void main(String[] args) {
            try (Scanner in = new Scanner(Aoc2023s18v2.class.getResourceAsStream("res/t18.txt"))) {
                List<String> rows = new ArrayList<>();
    
                while (in.hasNext()) {
                    String row = in.nextLine();
                    rows.add(row);
                }
                List<Point> polyPoints = polygons2(rows);
    
                System.out.println("found=" + calculateArea2(polyPoints));
    
            }
        }
    
        private static List<Point> polygons2(List<String> rows) {
            List<Point> points = new ArrayList<>();
            Point p = new Point(0, 0);
            points.add(p);
            for (String row : rows) {
                String dirKey = row.split(" ")[2];
                long factor = Long.valueOf(dirKey.substring(2, 7), 16);
                String dir = "" + dirKey.charAt(dirKey.length() - 2);
                System.out.println(factor + " " + dir);
                Point np = p.createRelative(DIRECTIONS.get(DIRECTIONS_TRAD.get(dir)), factor);
                points.add(np);
                p = np;
            }
            return points;
        }
    }
  • # J'étais fatigué, j'ai fait un algo moisie, j'ai du corrigé des bug moisie

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

    Mauvais cocktail pour coder :)
    - S'être couché à 3h
    - Être fatigué, limite reste de gueule bois
    - Regarder les conneries à la télé en même temps qu'on code.

    Conséquences:
    - çà donne un code très long à déboguer
    - un problème pris de travers.

    Mon code est tellement moche que je ne vais pas le partager :)

    Honnêtement , je ne voyais pas comment appliquer un algo traditionnel de pathfinding avec les règles de déplacement.
    Je suis donc partie sur une fonction récursive dans un premier temps. Mauvaise pioche entre les bogues, je suis arrivé après 3h à me dire que çà ne pouvait pas marcher.
    Je change de stratégie. Je pars de l'arrivé et je remonte progressivement en mettant à jour les noeuds adjacents, j'y ai passé encore bien 3h au total sur la journée.

    3min pour donner la réponse de la partie 2.

  • # Solution en Java 403ms

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

    Ci-dessous ma soluce en Java pour la partie 2. Elle met 403ms une fois Java lancé (c'est comme un bon diesel Java). Et encore, j'ai une vilaine boucle qui compte jusqu'à avant le milliard.
    J'optimise en utilisant des objets mutable & un bon vieux cache basé sur un Record.

    package aoc2023;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    public class Aoc2023s14v2 {     
        enum Type {
            SPHERE,
            ROCK;
        }
    
        public static class Point {
            int x;
            int y;
            Type type;
    
            public Point(int x, int y, Type type) {
                this.x= x;
                this.y=y;
                this.type = type;
            }
        }
    
        public static class World {
            int width;
            int height;
    
            Point[][] map;
            List<Point> spheres = new ArrayList<>();
    
    
            public World(List<String> rows) {
                map = new Point[rows.size()][rows.get(0).length()];
                for(int y=0;y < rows.size();y++) {
                    addRow(rows.get(y), y);
                }
                this.height = rows.size();
            }
    
            public void addRow(String row, int y) {
                this.width = row.length();
    
                for(int x=0;x < row.length();x++) {
                    Point p = null;
                    if(row.charAt(x) == 'O') {
                        p =new Point(x, y, Type.SPHERE);
                        spheres.add(p);
                    } else if(row.charAt(x) == '#') {
                        p = new Point(x, y, Type.ROCK);
                    }
    
                    map[y][x] =p;
                }
            }
    
            public boolean isFree(int x, int y) {
                if(x < 0 || x >= width || y < 0 || y >= height ) {
                    return false;
                }
    
                return this.map[y][x] == null;          
            }
    
            public Point find(int x, int y) {
                if(x < 0 || x >= width || y < 0 || y >= height ) {
                    return null;
                }
                return this.map[y][x];      
            }
    
            public void move(int dx, int dy) {
                boolean change = false;
                do {
                    change =false;
                    for(Point p : spheres) {
                        if(isFree(p.x + dx, p.y +dy)) {
                            map[p.y][p.x] = null;
                            p.x += dx;
                            p.y += dy;
                            map[p.y][p.x] = p;
                            change =true;
                        }
                    }               
                } while(change);            
            }
    
            public int computeWeight() {
                int sum = 0;
                for(Point sphere :spheres) {
                    sum += (height-sphere.y);
                }
                return sum;
            }
    
    
            public List<String> toRows() {
                List<String> rows = new ArrayList<>();
                StringBuilder sb = new StringBuilder();
                for(int y=0;y < height;y++) {
                    sb.setLength(0);
                    for(int x=0;x < width;x++) {
                        Point p = find(x, y);
                        if(p == null) {
                            sb.append('.');
                        } else if(p.type == Type.ROCK) {
                            sb.append('#');
                        } else {
                            sb.append('O');
                        }
                    }
                    rows.add(sb.toString());
                }
                return rows;
            }
        }
    
        public static void main(String[] args) {        
            long startMs = System.currentTimeMillis();          
            try (Scanner in = new Scanner(Aoc2023s14v2.class.getResourceAsStream("res/t14.txt"))) {
                List<String> rows = new ArrayList<>();
                while (in.hasNext()) {
                    rows.add(in.nextLine());
                }
    
                Integer startCycle = null;
                Integer cycleCount = null;
                World world = null;
                final long LOOPS = 1_000_000_000L;
                for(long x = 0 ;x < LOOPS;x++) {
                    CacheKey current = new CacheKey(rows);
                    if(keys[current.cacheIndex()] != null && keys[current.cacheIndex()].equals(current)) {
                        if(startCycle == null) {
                            startCycle = current.cacheIndex();
                            cycleCount = 0;
                        } else if(startCycle == current.cacheIndex()) {
                            System.out.println("Make cycle: " + cycleCount);
                            // Could be more elegant :)
                            while(x < (LOOPS-cycleCount)) {
                                x += (cycleCount+1);
                            }
                        } else {
                            cycleCount++;
                        }
                        world = cache_worlds[current.cacheIndex()];
                    } else {
                        world = computeWorld(rows);
                        keys[current.cacheIndex()] = current;
                        cache_worlds[current.cacheIndex()] = world;
                        System.out.println("miss " + x);
    
                        startCycle = null;
                        cycleCount = null;
                    }
                    rows = world.toRows();              
                }
    
                System.out.println(world.computeWeight());
            }   
            System.out.println((System.currentTimeMillis() - startMs) + "ms");
        }
    
        private static World computeWorld(List<String> rows) {
            World world;
            world = new World(rows);
            world.move(0, -1);
            world.move(-1, 0);
            world.move(0, 1);
            world.move(1, 0);
            return world;
        }
    
        public static record CacheKey(List<String> rows) {
    
            public int cacheIndex() {
                return Math.abs(this.hashCode()) % CACHE_SIZE;
            }
        }
    
        public static final int CACHE_SIZE = 1_000_000;
        public static  CacheKey[] keys = new CacheKey[CACHE_SIZE];
        public static  World[] cache_worlds = new World[CACHE_SIZE];
    
    }
  • # J'en ai bavé.

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

    6h au total ! J'ai commencé par prendre le problème de travers.

    J'ai fait substitution récursive des '?' ,c'était mon erreur.

    C'est après que j'ai compris qu'il fallait distribuer les espaces restant entre les groupes.

    çà permet d'exprimer le problème avec une fonction recursive pour lequel on peut mettre en place un cache des valeurs par rapport au reste à évaluer.

    Environ 414ms sur ma machine (après avoir commenté les println)

    package aoc2023;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Scanner;
    import java.util.concurrent.atomic.AtomicLong;
    
    public class Aoc2023s12v4 { 
        public static record Evaluation(List<Integer> groupes, int totalDot, String dstSpring) {                    
        }
    
        public static Evaluation[] cache = new Evaluation[1_000_000];
        public static long[] cacheValue = new long[1_000_000];
    
        public static void main(String[] args) {                        
            assert (countExpandedPossibility("??# 2") == 16L);
    
            assert (countExpandedPossibility("???.### 1,1,3") == 1L); 
            assert (countExpandedPossibility(".??..??...?##. 1,1,3") == 16384L);
            assert (countExpandedPossibility("????.#...#... 4,1,1") == 16L);
            assert (countExpandedPossibility("????.######..#####. 1,6,5") == 2500L);
            assert (countExpandedPossibility("?###???????? 3,2,1") == 506250L);
            //assert (countExpandedPossibility("???.?#?????##?#????? 1,2,7,1") == 506250L);
    
            System.out.println("-----------          -----------");
            System.out.println("----------- END TEST -----------");
            System.out.println("-----------          -----------");
    
    
            try (Scanner in = new Scanner(Aoc2023s12v4.class.getResourceAsStream("res/t12.txt"))) {
                List<String> map = new ArrayList<>();
    
                while (in.hasNext()) {
                    String row = in.nextLine();
                    map.add(row);
                }
    
                long count = 0;
    
                for (String row : map) {
                    count += countExpandedPossibility(row);
                }
                System.out.println(count);
            }
        }
        private static long countExpandedPossibility(String row) {
            String srcSprings = row.split(" ")[0];
            int[] srcRules = Arrays.stream(row.split(" ")[1].split(",")).mapToInt(s -> Integer.parseInt(s)).toArray();
    
            long r = countExpanded(srcSprings, srcRules, 5);
            System.out.println(r);
            return r;
        }
        private static long countExpanded(String srcSprings, int[] srcRules, int i) {
            int[] dstRules = new int[srcRules.length * 5];
            for (int x = 0; x < i; x++) {
                for (int y = 0; y < srcRules.length; y++) {
                    dstRules[x * srcRules.length + y] = srcRules[y];
                }
            }
    
            String dstSpring = srcSprings;
            for(int x=0;x < i-1;x++) {
                dstSpring += '?' + srcSprings;
            }               
            System.out.println("Pattern:");
            System.out.println(dstSpring);
    
            int total = Arrays.stream(dstRules).sum();
            int totalDot = dstSpring.length() - total;
    
            System.out.println(total + " + " + totalDot + " => " + dstSpring.length());
    
    
            return distributeDotBetweenGroup(
                    Arrays.stream(dstRules).mapToObj(Integer::valueOf).toList(),
                    true,
                    totalDot,               
                    dstSpring);             
        }
        private static long distributeDotBetweenGroup(List<Integer> groupes, boolean first, int totalDot, String dstSpring) {           
            if(0 == groupes.size() ) {
                String current = "";
                for(int j=0;j < totalDot;j++) {
                    current += '.';
                }
                //System.out.println(sb);
                if(match(current, dstSpring)) {             
                    return 1;           
                }
                return 0;
            }
    
            int size = groupes.get(0);
    
            StringBuilder sb = new StringBuilder();
            long sum  = 0;
            for(int ud=(first? 0:1);ud <= totalDot;ud++) {
                sb.setLength(0);            
                for(int j=0;j < ud;j++) {
                    sb.append('.');             
                }           
                for(int j=0;j < size;j++) {
                    sb.append('#');
                }
    
    
                if(! match(sb, dstSpring, sb.length())) {
                    continue;
                }
    
                Evaluation eva= new Evaluation(groupes.subList(1, groupes.size()), totalDot-ud, dstSpring.substring(sb.length()));
    
                int indexCache =Math.abs(eva.hashCode())% cache.length;
                if(cache[indexCache] !=null && cache[indexCache].equals(eva)) {
                    sum += cacheValue[indexCache];
                } else {
                    long i= distributeDotBetweenGroup(eva.groupes, false, eva.totalDot, eva.dstSpring);
                    cache[indexCache] = eva;
                    cacheValue[indexCache] = i;
                    sum += i;
                }           
    
            }
            return sum;
    
        }
        private static boolean match(String test, String refPattern) {
            if(test.length() != refPattern.length()) {
                return false;
            }
            for (int x = 0; x < test.length(); x++) {
                char c = refPattern.charAt(x);
                if (c != '?') {
                    if (test.charAt(x) != c) {
                        return false;
                    }
                }
            }
            return true;
        }
        private static boolean match(StringBuilder test, String refPattern, int wi) {       
            for (int x = 0; x < wi; x++) {
                char c = refPattern.charAt(x);
                if (c != '?') {
                    if (test.charAt(x) != c) {
                        return false;
                    }
                }
            }
            return true;
        }
    }
  • # Ma solution

    Posté par  . En réponse au message Advent of Code 2023 : Jour 10. Évalué à 1.

    Pour la deuxième partie, j'ai opté pour une solution où je remplace les tuiles de base par des tuiles de 3x3
    Je remplie ensuite en faisant les cellules en bordure de la map.

    Note: Ce code doit être utilisée --Xms2G pour avoir une stack plus grande que celle par défaut.

    package aoc;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.Stack;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.util.stream.Collectors;
    
    import aoc.Aoc2023s10p1.Direction;
    import aoc.Aoc2023s10p1.Maze;
    import aoc.Aoc2023s10p1.Pipe;
    
    public class Aoc2023s10p2 {
        public enum Direction {
            N(0, -1), S(0, 1), E(1, 0), W(-1, 0);
    
            int dx;
            int dy;
    
            Direction(int dx, int dy) {
                this.dx = dx;
                this.dy = dy;
            }
    
            Direction comeFrom() {
                if (this == N) {
                    return S;
                } else if (this == E) {
                    return W;
                } else if (this == W) {
                    return E;
                } else if (this == S) {
                    return N;
                }
                throw new RuntimeException();
            }
        }
        public enum Pipe {
    
            V('|', Arrays.asList(Direction.N, Direction.S),
                    new int[][] {new int[]{0, 1, 0}, new int[]{0, 1, 0}, new int[]{0, 1, 0}}
                    ), // is a vertical pipe connecting north and south.
            H('-', Arrays.asList(Direction.E, Direction.W),
                    new int[][] {new int[]{0, 0, 0}, new int[]{1, 1, 1}, new int[]{0, 0, 0}}
                    ), // is a horizontal pipe connecting east and west.
            L('L', Arrays.asList(Direction.N, Direction.E),
                    new int[][] {new int[]{0, 1, 0}, new int[]{0, 1, 1}, new int[]{0, 0, 0}}
                    ), // , is a 90-degree bend connecting north and east.
            J('J', Arrays.asList(Direction.N, Direction.W),
                    new int[][] {new int[]{0, 1, 0}, new int[]{1, 1, 0}, new int[]{0, 0, 0}}
                    ), // is a 90-degree bend connecting north and west.
            _7('7', Arrays.asList(Direction.S, Direction.W),
                    new int[][] {new int[]{0, 0, 0}, new int[]{1, 1, 0}, new int[]{0, 1, 0}}
                    ), // is a 90-degree bend connecting south and west.
            F('F', Arrays.asList(Direction.S, Direction.E),
                    new int[][] {new int[]{0, 0, 0}, new int[]{0, 1, 1}, new int[]{0, 1, 0}}
                    ), // is a 90-degree bend connecting south and east.
            D('.', Collections.emptyList(),
                    new int[][] {new int[]{0, 0, 0}, new int[]{0, 0, 0}, new int[]{0, 0, 0}}
                    ), // is ground; there is no pipe in this tile.
            S('S', Arrays.asList(Direction.N, Direction.S, Direction.E, Direction.W),
                    new int[][] {new int[]{0, 1, 0}, new int[]{1, 1, 1}, new int[]{0, 1, 0}}
                    ),// is the starting position of the
                                                                                        // animal; there is a pipe on this
                                                                                        // tile, but your sketch doesn't
                                                                                        // show what shape the pipe has.
            ;
    
            char c;
            List<Direction> directions;
            int[][] matrix;
    
            Pipe(char c, List<Direction> directions, int[][] matrix) {
                this.c = c;
                this.directions = directions;
                this.matrix = matrix;
            }
    
            boolean acceptFrom(Direction d) {
                return directions.contains(d);
            }
        }
        public static class Maze2 {
            List<List<Pipe>> maze;
            final int heightMap;
            final int widthMap;
            final int[][] map;
            final int[][] weights;
    
            final int[][] externs;
    
            Maze2(List<List<Pipe>> maze) {
                this.maze = maze;
    
                int height = maze.size();
                int width = maze.get(0).size();     
                weights = new int[height][width];
                computeWeight();
    
                heightMap = height*3;
                widthMap = width*3;
                map = new int[heightMap][widthMap];
                externs = new int[heightMap][widthMap];
                for (int x = 0; x < width; x++) {
                    for (int y = 0; y < height; y++) {
    
                        if(weights[y][x] != Integer.MAX_VALUE) {
                            writeMatrix(maze, x, y);
                        }
                    }
                }
    
                for (int x = 0; x < widthMap; x++) {
                    for (int y = 0; y < heightMap; y++) {
                        externs[y][x] = -1;
                        if (map[y][x] == 1) {
                            externs[y][x] = 0;
                        }
    
                    }
                }
    
                for (int x = 0; x < widthMap; x++) {
                    fillEnclosed(x, 0);
                    fillEnclosed(x, heightMap - 1);
                }
    
                for (int y = 0; y < heightMap; y++) {
                    fillEnclosed(0, y);
                    fillEnclosed(widthMap - 1, y);
                }
    
            }
    
            private void writeMatrix(List<List<Pipe>> maze, int x, int y) {
                Pipe p = maze.get(y).get(x);
                for (int dy = 0; dy < 3; dy++) {
                    for (int dx = 0; dx < 3; dx++) {
                        int m = p.matrix[dy][dx];
                        map[y*3 +dy][x*3 + dx] = m;
                    }
                }
            }
    
            private void fillEnclosed(int x, int y) {
                if (x < 0 
                        || x >= widthMap 
                        || y < 0 
                        || y >= heightMap) {
                    return;
                }
                if (map[y][x] == 1) {
                    return;
                }
    
                if (externs[y][x] < 0) {
                    externs[y][x] = 1;
    
                    for (Direction d : Direction.values()) {
                        fillEnclosed(x + d.dx, y + d.dy);
                    }               
                }
            }
    
            public void print() {
                for(int y=0;y < heightMap;y++) {
                    for(int x=0;x < widthMap;x++) {
                        System.out.print(map[y][x]);
                    }
                    System.out.println();
                }
    
                for(int y=0;y < heightMap;y++) {
                    for(int x=0;x < widthMap;x++) {
                        int i = externs[y][x];
                        if(i < 0) {
                            System.out.print("I");
                        } else if(i == 0) {
                            System.out.print("#");
                        } else {
                            System.out.print(".");
                        }
    
                    }
                    System.out.println();
                }
            }
    
            public int countEnclosed() {
                int max = 0;
                int height = maze.size();
                int  width= maze.get(0).size(); 
                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
    
                        if(emptyTile(x, y)) {
                            max++;
                        }       
                    }
                }
                return max;
            }
    
            public boolean emptyTile(int x, int y) {
                for (int dy = 0; dy < 3; dy++) {
                    for (int dx = 0; dx < 3; dx++) {
    
                        if(externs[y*3+dy][x*3+dx] >= 0) {
                            return false;
                        }
                    }
                }
                return true;
            }
    
            public void computeWeight() {
                int height = maze.size();
                int width = maze.get(0).size(); 
    
                int sx = 0;
                int sy = 0;
                for(int x=0;x < width;x++) {
                    for(int y=0;y < height;y++) {
                        weights[y][x] = Integer.MAX_VALUE;
                        if(maze.get(y).get(x) == Pipe.S) {
                            weights[y][x] = 0;
                            sx = x;
                            sy = y;
                        }
                    }
                }
    
                fillWeightFrom(sx, sy);
            }
    
            private void fillWeightFrom(int cx, int cy) {
                int w = weights[cy][cx];
                Pipe currentPipe = this.maze.get(cy).get(cx);
    
                for(Direction d : Direction.values()) {
    
                    if(currentPipe.directions.contains(d)) {
                        int dx = cx+ d.dx;
                        int dy = cy+ d.dy;
                        Pipe nextPipe = next(dx, dy);
                        if(nextPipe != null) {
                            if(nextPipe.acceptFrom(d.comeFrom())) {
                                int wn = weights[dy][dx];
                                if(wn > (w+1)) {
                                    weights[dy][dx] = w+1;
                                    fillWeightFrom(dx, dy);
                                }
                            }
                        }
                    }               
                }       
            }
    
            public Pipe next(int cx, int cy) {
                int height = maze.size();
                int width = maze.get(0).size(); 
                if(cx < 0 || cx >= width) {
                    return null;
                }
                if(cy < 0 || cy >= height) {
                    return null;
                }
    
                return this.maze.get(cy).get(cx);
            }
        }
        public static Map<String, Pipe> pipeBySymbol = Arrays.stream(Pipe.values())
                .collect(Collectors.toMap(p -> "" + p.c, p -> p));
        public static void main(String[] args) {
    
            try (Scanner in = new Scanner(Aoc2023s10p2.class.getResourceAsStream("res/Aoc2023s10p1.txt"))) {
                String row;
                List<List<Pipe>> maze = new ArrayList<>();
                while (in.hasNext()) {
                    row = in.nextLine();
    
                    maze.add(row.chars().mapToObj(i -> pipeBySymbol.get(String.valueOf((char) i))).toList());
    
                }
    
                Maze2 mazeSolve = new Maze2(maze);
                mazeSolve.print();
                System.out.println(mazeSolve.countEnclosed());
            }
        }
    
    }
  • # Je me lance ma soluce en Java

    Posté par  . En réponse au message Advent of Code 2023 : Day 3. Évalué à 1.

    Un peu long à coder, j'ai passé plus de temps sur la première partie que sur la deuxième partie.

    Partie 1 :

    public class Aoc2023s3p1 {
        public static void main(String[] args) {
            try(Scanner in = new Scanner(Aoc2023s3p1.class.getResourceAsStream("res/Aoc2023s3p1.txt"))) {
                    String row;
                    int sum =0;
    
                    List<String> rows = new ArrayList<>();
    
                    while(in.hasNext()) {
                        row = in.nextLine();
                        rows.add(row);
                    }
    
                    for(int x=0;x < rows.size();x++) {
                        sum += check(x, rows);
                    }
    
    
                    System.out.println(sum);
            }
        }
    
        public static record Num(int start, int end, String data) {
        }
    
    
        public static int check(int rowIndex, List<String> rows) {
    
            String row = rows.get(rowIndex);
    
            List<Num> list = new ArrayList<>();
            Integer start = null;
            for(int x=0;x < row.length();x++) {
                int c = row.charAt(x) - '0';
                if(Character.isDigit(row.charAt(x))) {
                    if(start == null) {
                        start = x;
                    }
                } else {
                    if(start != null) {
                    list.add(new Num(start, x, row.substring(start, x)));
                    start = null;
                    }
                }
            }
    
            if(start !=null) {
                list.add(new Num(start, row.length(), row.substring(start)));
            }
    
            int sum = 0;
            for(Num num : list) {
                System.out.println(num);
                if(checkNum(num, rowIndex, rows)) {
                    System.out.println("OK");
                    sum += Integer.parseInt(num.data());
                }
            }
    
            return sum;
        }
    
    
        private static boolean checkNum(Num num, int rowIndex, List<String> rows) {
            int before = num.start-1;
            if(checkCharacter(rowIndex, before, rows)) {
                return true; 
            }
    
            if(checkCharacter(rowIndex, num.end, rows)) {
                return true; 
            }
    
    
            for(int x = num.start-1;x < num.end+1;x++) {
                if(checkCharacter(rowIndex - 1, x, rows)
                        || checkCharacter(rowIndex + 1, x, rows)) {
                    return true;
                }
            }
            return false;
        }
    
        private static boolean checkCharacter(int rowIndex, int colIndex, List<String> rows) {
            if(rowIndex < 0 || rowIndex >= rows.size()) {
                return false;
            }
            String row = rows.get(rowIndex);
    
            if(colIndex < 0 || colIndex >= row.length()) {
                return false;
            }
    
            char c = row.charAt(colIndex);
            if(Character.isDigit(c) || c == '.') {
                return false;
            }
    
            return true;
        }
    
    }

    Pour la partie 2, l'idée est assez simple. J'identifie les engrenages '*' par leurs coordonnées et je stocke sur chaque coordonnée la liste des nombres associés (numsById)

    public class Aoc2023s3p2 {
        public static Map<Coord, List<Num>> numsById = new HashMap<>();
    
        public static void main(String[] args) {
    
            try(Scanner in = new Scanner(Aoc2023s3p2.class.getResourceAsStream("res/Aoc2023s3p1.txt"))) {
                    String row;
    
    
                    List<String> rows = new ArrayList<>();
    
                    while(in.hasNext()) {
                        row = in.nextLine();
                        rows.add(row);
                    }
    
                    for(int x=0;x < rows.size();x++) {
                        check(x, rows);
                    }
    
    
                    int sum =0;
                    for(List<Num> nums: numsById.values()) {
    
                        if(nums.size() <= 1) {
                            continue;
                        }
                        System.out.println("=====");
                        int prod = 1;
                        for(Num num : nums) {
                            prod *= Integer.parseInt(num.data);
                            System.out.println(num.data);
                        }
                        System.out.println("=>" + prod);
                        sum += prod;
                    }
    
                    System.out.println(sum);
            }
        }
    
        public static record Num(int start, int end, String data) {
        }
    
    
        public static void check(int rowIndex, List<String> rows) {
            String row = rows.get(rowIndex);
    
            List<Num> list = new ArrayList<>();
            Integer start = null;
            for(int x=0;x < row.length();x++) {
                int c = row.charAt(x) - '0';
                if(Character.isDigit(row.charAt(x))) {
                    if(start == null) {
                        start = x;
                    }
                } else {
                    if(start != null) {
                    list.add(new Num(start, x, row.substring(start, x)));
                    start = null;
                    }
                }
            }
    
            if(start !=null) {
                list.add(new Num(start, row.length(), row.substring(start)));
            }
    
            for(Num num : list) {
                System.out.println(num);
                if(isGearPart(num, rowIndex, rows)) {
                    System.out.println("OK");
                }
            }
    
    
        }
    
    
        private static boolean isGearPart(Num num, int rowIndex, List<String> rows) {
    
    
            int before = num.start-1;
            checkGear(num, rowIndex, before, rows);
            checkGear(num, rowIndex, num.end, rows);
    
    
            for(int x = num.start-1;x < num.end+1;x++) {
                checkGear(num, rowIndex - 1, x, rows);
                checkGear(num, rowIndex + 1, x, rows);
            }
    
    
    
            return false;
        }
    
    
        public static record Coord(int rowIndex, int colIndex) {
    
        }
    
        private static boolean checkGear(Num num, int rowIndex, int colIndex, List<String> rows) {
            if(rowIndex < 0 || rowIndex >= rows.size()) {
                return false;
            }
            String row = rows.get(rowIndex);
    
            if(colIndex < 0 || colIndex >= row.length()) {
                return false;
            }
    
            char c = row.charAt(colIndex);
            if(c == '*') {
                numsById.computeIfAbsent(new Coord(rowIndex, colIndex),k->new ArrayList<>()).add(num);
    
            }
    
            return false;
        }
    
    }
  • [^] # Re: Plusieurs leaderboards privés ?

    Posté par  . En réponse au journal Advent of code 2023. Évalué à 3.

    Je confirme. On a un leadboard interne à ma boite. Plus celui-ci.

  • [^] # Re: J'y retourne !

    Posté par  . En réponse au journal Advent of code 2023. Évalué à 4.

    J'aurai du te laisser faire la news :-p

  • # Personnellement, je préfère les tomates aux pattates

    Posté par  . En réponse au journal Il est temps que la communauté internationale fasse un choix. Évalué à 2.

    Alors pour moi, une bonne raclette:
    - Bcp de fromages
    - Des Tomates
    - De l'oignon coupé finement.
    - Un gouse d'ail cuite en même que les patates
    - Un peu de patates (pas plus d'une pour moi)
    - Un peu de jambon fumé et du bacon

    Et sinon pour la problématique de l'appareil à Raclette , il y a ceux de GIFI qui se branche les un les autres. Donc tout le monde peut venir avec ses appareils à raclette.

  • # J'adore

    Posté par  . En réponse au journal Grandbrothers. Évalué à 2.

    J'adore :) Merci pour cette belle découverte.

  • # Ça dépend

    Posté par  . En réponse à la dépêche Pétition de Mozilla pour protéger Firefox. Évalué à 1.

    Si, c'est comme dans l'article, c'est à dire:
    - le navigateur récupère une black list du gouvernement , çà me va.

    Par contre, si le système est du type. Quand on consulte un site, on vient demander au site du gouvernement si on a le droit d'y accéder, c'est plus ennuyeux.
    Pour 3 raisons:
    - le gouvernement connaitra ton historique de navigation
    - ça risque de tuer les perf de navigation
    - une ddos sur site , on ne navigue plus

    Après, c'est le genre de feature qui pourra se désactiver. Vu qu'elle ne sera pas appliquable dans tous les pays.

    Après pour l histoiriques de navigation, les antivirus, google, ils ont déjà cette historique avec l antiphishing d activés donc c est plutôt le risque 2 et 3 qui gène

  • # embrace - extend - extinguish

    Posté par  . En réponse au journal Wayland dans windows 10 et 11. Évalué à 2.

    J'ai découvert moi aussi WSL 2 sur Windows. çà me permet de faire tourner un Linux & plein d'instance docker pour mes dev.

    Je n'ai pas encore essayé de faire tourner des apps graphique mais je ne suis pas surpris que çà marche.

    Ce qui me terrifie, c'est la stratégie historique de Microsoft: Embrace - Extend - Extinguish.

    Avec, ils ont réussi à bouffer : OS/2 , Netscape, …

  • [^] # Re: Mailcow ?

    Posté par  . En réponse au message Serveur smtp/map. Évalué à 1.

    Merci pour l'info.

    Au final, je pense que je vais partir avec une image docker de postfix maison ou de sendmail maison.

  • [^] # Re: Mailcow ?

    Posté par  . En réponse au message Serveur smtp/map. Évalué à 1.

    Merci pour le lien.
    J'aurai préféré un témoignage genre çà marche chez moi :)

    çà a l'air de faire trop de truc pour moi. Mon besoin est beaucoup plus simple.

  • # Perso, j'y connais rien Ruby mais ...

    Posté par  . En réponse au lien OneTimeSecret. Évalué à 0.

    Je trouve que l'idée est bonne.

    Par contre, ce qui me gène, c'est que je n'y connais rien Ruby & que pour utiliser ce genre de service.
    il faut que je sois sur que cela soit Safe. il faut donc que je l'audit.

    Il faudrait le même service dans un code qui tient en quelques fichiers facilement auditable sans dépendance tiers.
    - 1 fichier sources serveur
    - 1 form HTML
    - 1 JS
    - 1 form CSS
    - 1 Dockerfile

  • [^] # Re: J'ai galéré :)

    Posté par  . En réponse au message Avent du code jour 25. Évalué à 2.

    Yes bien joué Yth

    Bien joué tt le monde.

    Je trouve qu il etait vraiment plus simple que l'an dernier.

    Le prochain challenge sympa dans ce genre, c est ctf de l Ansi en mai.

  • # J'ai galéré :)

    Posté par  . En réponse au message Avent du code jour 25. Évalué à 2. Dernière modification le 25 décembre 2022 à 11:52.

    Environ 2h40 pour faire ce fichu dernier problème. Je genre d'éxercice, ce n'est vraiment pas mon truc.

    J'y suis allé à la méthode ajustement test unitaire.

    Le parsing est assez simple à réaliser. En gros, c'est comme une conversion d'une base 5 avec des -1 , et -2 :)

    Le problème, c'est l'opération inverse. Mon algo est tellement tordu que je n'arrive pas à l'expliquer :)
    Je n'ai même pas l'excuse de l'alcool car je suis sous antibiotique. Résultat, c'est mon premier noël sans une goutte d'alcool.

    Joyeux noël à tous.

        static String toSnafu(long v) {
            String s  =Long.toString(v, 5);
            if(s.indexOf("3") < 0 && s.indexOf("4") < 0) {
                return s;
            }
            long[] seek = prepareSeek(v);
            long seekValue = seek[0] * ((long)Math.pow(5, seek.length-1));
    
            for(int x=1;x < seek.length;x++) {
                long lowestGreater = 2;
                for(int e=VALUES.length-1;e >= 0;e--) {
    
    
                    long add = VALUES[e] * ((long)Math.pow(5, seek.length-1-x));
    
                    long s1 = seekValue + add + maxWithOnly2(seek.length-1-x) ;
                    long s2 = v;
    
    
                    if(s1 < s2) {                   
                        break;
                    }
    
                    lowestGreater = VALUES[e];
    
                }
    
    
    
                seek[x] = lowestGreater;
                //System.out.println(Arrays.stream(seek).mapToObj(i->Long.toString(i)).collect(Collectors.joining(",")));
                long add = lowestGreater * ((long)Math.pow(5, seek.length-1-x));
                seekValue += add;
            }
    
    
    
    
            return seekToString(seek);
        }
    
    
        private static String seekToString(long[] seek) {
            StringBuilder sb = new StringBuilder();
            for(int x=0;x < seek.length;x++) {
                if(seek[x] == 0 && x == 0) {
                    continue;
                }
    
                if(seek[x] == -2) {
                    sb.append('=');
                } else if(seek[x] == -1) {
                    sb.append('-');
                } else {
                    sb.append(Long.valueOf(seek[x]));
                }
    
            }
    
            return sb.toString();
        }
    
        static long[] prepareSeek(long v) {
            if(v == 0) {
                return new long[] {0};
            }
            long power = 0;
            boolean greater = false;
            long greaterNb = 0;
            while(! greater) {
                long max = maxWithOnly2(power);
    
                for(long x=1; x <= 2;x++) {
                    long l = (x* ((long)Math.pow(5, power))) +max ;
                    if(l >= v) {
                        greater =true;
                        greaterNb = x;
                        break;
                    }
                }
                power += 1;
            }
    
            long[] mask = new long[(int)power];
            mask[0]=greaterNb;
            return mask;
        }
    
    
        private static long maxWithOnly2(long power) {
            long max = 0;
            for(int j=0; j < power;j++) {
                max += 2* Math.pow(5, j);
            }
            return max;
        }
  • # Parcours en largeur.

    Posté par  . En réponse au message Avent du Code, jour 24. Évalué à 5.

    On est dans le cas typique d'un parcours en largeur d'un arbre des possibles.

    A chaque round, on regarde l'ensemble des actions possibles et on calcule les états suivants en fonction de ses possibilités
    il y a des branches qui s'élimine d'elle-même car il n'y a plus d'action possible pour le joueur.
    il y aussi des branches qui se rejoingne car il y a plusieurs chemin pour arriver à un même état.
    J'utilise le hashCode/equals de mon State pour les dédupliquer sinon çà explose grave.

    Au total,j'ai mis 1h50 pour debug les différentes conneries que j'ai fait à mon réveille.

    Je mets 40s pour calculer la solution de la 2ème étoiles

    Maintenant, je vais aller braver les magasins car j'ai plein de cadeau à acheter :-).
    Joyeux Noël à tous.

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Objects;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    public class A2022D24 {
        public enum Move {
            EAST(1, 0, '>'),
    
            SOUTH(0, 1, 'v'), WEST(-1, 0, '<'), WAIT(0, 0, 'W'), NORTH(0, -1, '^');
    
            int dx;
            int dy;
            char d;
    
            private Move(int dx, int dy, char d) {
                this.dx = dx;
                this.dy = dy;
                this.d = d;
            };
    
        }
    
        public static class Point {
            int x;
            int y;
    
            public Point() {
            }
    
            public Point(int x, int y) {
                this.x = x;
                this.y = y;
            }
    
            public String toString() {
                return x + "," + y;
            }
    
            public void copyInto(Point p) {
                p.x = this.x;
                p.y = this.y;
            }
    
            @Override
            public int hashCode() {
                return Objects.hash(x, y);
            }
    
            @Override
            public boolean equals(Object obj) {
                if (this == obj)
                    return true;
                if (obj == null)
                    return false;
                if (getClass() != obj.getClass())
                    return false;
                Point other = (Point) obj;
                return x == other.x && y == other.y;
            }
    
    
        }
    
        public static class Wind extends Point {
            Move m;
    
            public Wind(int x, int y) {
                this.x = x;
                this.y = y;
            }
    
            public void copyInto(Wind wind) {
                super.copyInto(wind);
                wind.m = m;
    
            }
    
        }
    
        public static class State {
            List<Wind> winds = new ArrayList<>();
            Point pos = new Point(1, 0);
            int round = 0;
    
            public void copyInto(State state) {
                state.winds.clear();
                for (Wind w : this.winds) {
                    Wind newWind = new Wind(0, 0);
                    w.copyInto(newWind);
                    state.winds.add(newWind);
                }
    
                this.pos.copyInto(state.pos);
                state.round = this.round;
    
            }
    
            public char count(int x, int y) {
                char c = '.';
                int count = 0;
                for (Wind wind : this.winds) {
                    if (wind.x == x && wind.y == y) {
                        count++;
                        c = wind.m.d;
                    }
                }
                if(count > 1) {
                    c = ("" + count).charAt(0);
                }
                return c;
    
            }
    
            public boolean isFree(int x, int y) {
                if ((x == WIDTH - 2) && (y == HEIGHT - 1)) {
                    return true;
                }
    
                if ((x == 1) && (y == 0)) {
                    return true;
                }
    
                if (y <= 0 || x <= 0 || x >= (WIDTH - 1) || y >= (HEIGHT - 1)) {
                    return false;
                }
    
                for (Wind wind : this.winds) {
                    if (wind.x == x && wind.y == y) {
                        return false;
                    }
                }
                return true;
    
            }
    
            public List<A2022D24.Move> getAvailables() {
                return Arrays.stream(Move.values()).filter(m -> isFree(pos.x + m.dx, pos.y + m.dy))
                        .collect(Collectors.toList());
            }
    
            public void moveWind() {
                for (Wind wind : winds) {
                    wind.x = wind.x + wind.m.dx;
                    wind.y = wind.y + wind.m.dy;
    
                    if (wind.x == 0) {
                        wind.x = WIDTH - 2;
                    } else if (wind.x == WIDTH - 1) {
                        wind.x = 1;
                    }
    
                    if (wind.y == 0) {
                        wind.y = HEIGHT - 2;
                    } else if (wind.y == HEIGHT - 1) {
                        wind.y = 1;
                    }
                }
            }
    
            public void print() {
                for (int y = 0; y < HEIGHT; y++) {
                    for (int x = 0; x < WIDTH; x++) {
    
                        if (x == pos.x && y == pos.y) {
                            System.out.print("E");
                        } else if (isFree(x, y)) {
                            System.out.print(".");
                        } else if(x == 0 || x == (WIDTH-1) || y == 0 || y == HEIGHT-1) {
                            System.out.print("#");
                        } else {
                            System.out.print(count(x, y));
                        }
    
                    }
                    System.out.println();
                }
            }
    
            @Override
            public int hashCode() {
                return Objects.hash(pos, round);
            }
    
            @Override
            public boolean equals(Object obj) {
                if (this == obj)
                    return true;
                if (obj == null)
                    return false;
                if (getClass() != obj.getClass())
                    return false;
                State other = (State) obj;
                return Objects.equals(pos, other.pos) && round == other.round;
            }
        }
    
        public static void main(String[] args) {
            step1();
        }
    
        public static int WIDTH = 0;
        public static int HEIGHT = 0;
    
        private static void step1() {
            List<Wind> winds = new ArrayList<>();
    
            try (Scanner in = new Scanner(A2022D24.class.getResourceAsStream("/res/i24.txt"))) {
                int y = 0;
                while (in.hasNext()) {
                    String row = in.nextLine();
    
                    for (int x = 0; x < row.length(); x++) {
                        final char d = row.charAt(x);
    
                        Move blizzard = Arrays.stream(Move.values()).filter(c -> {
                            return c.d == d;
                        }).findAny().orElse(null);
    
                        if(blizzard != null) {
                            Wind wind = new Wind(x, y);
                            wind.m = blizzard;
                            winds.add(wind);
                        }
    
                    }
                    WIDTH = row.length();
                    y++;
                }
    
                HEIGHT = y;
    
    
    
                State state = new State();
                state.pos = new Point(1, 0);
                state.winds = winds;
    
    
                int round = 0;
                int targetX = WIDTH-2;
                int targetY = HEIGHT-1;
                state = foundSolution(state, targetX, targetY);
    
                state = foundSolution(state, 1, 0);
                state = foundSolution(state, targetX, targetY);
                System.out.println(state.round);
            }
        }
    
        private static State foundSolution(State start, int targetX, int targetY) {
            Set<State> previous = new HashSet<>();
    
            previous.add(start);
            Set<State> next = new HashSet<>(); 
    
            Set<State> tmp;
            State state;
            while(true) {
                System.out.println("States stack:" + previous.size() + " round:" + previous.iterator().next().round);
                next.clear();
                for(State s :previous) {
                    if(s.pos.x == targetX && s.pos.y == targetY)  {
                        return s;
    
                    }
    
    
                    explore(next, s);
                }
    
                tmp = previous;
                previous = next;
                next = tmp;
            }
        }
    
        private static void explore(Set<State> next,  A2022D24.State state) {
    
            //state.print();
            state.moveWind();
            List<Move> moves = state.getAvailables();
            if(moves.size() == 0) {
                //System.out.println("empty");
            }
    
            for (Move move : moves) {
                State newState = new State();
                state.copyInto(newState);
                newState.pos.x += move.dx;
                newState.pos.y += move.dy;
                newState.round++;
    
                if (!newState.isFree(newState.pos.x, newState.pos.y)) {
                    throw new RuntimeException(); 
                }
    
                next.add(newState);
            }
    
        }
    }
  • # Dans l'ensemble, c'est plus simple que l'an dernier

    Posté par  . En réponse au message Avent du Code, jour 23. Évalué à 2.

    Dans l'ensemble, ils sont tous beaucoup plus simple que l'an dernier.

    Environ 1h40 après 12h de voiture + ma crève qui ne me lâche pas, on va dire que çà aurait pu être pire.

    Dans l'ensemble , il n'y a rien de compliqué aujourd'hui. Il faut juste conserver à l'esprit toutes les petites règles qui ne sont pas flag en gras dans la description.

    Résultat, j'ai perdu 30min à comprendre que quand il n'y a pas d'Elf autour. Il ne bouge pas.

    La deuxième partie, elle ne rajoute rien de dur, je m'attendais à une règle genre distance, ou un truc qui faisait exploser la volumétrie.

    Mais non rien, j'ai juste lancé mon programme pas du tout optimisé en me disant il va falloir que je trouve une opti.
    Je n'ai pas eu le temps de finir d'écrire la première opti que j'avais déjà la solution.

    1min20 pour 1014 round

  • # Il était vraiment sympa celui-ci :-)

    Posté par  . En réponse au message Avent du Code, jour 22. Évalué à 1.

    Environ 4h-4h30 effectif dessus.
    La première partie est fastidieuse, mais çà se code bien (~2h)

    La deuxième partie est encore plus fastidieuse.
    J'ai opté pour une classe "Arrete" agrégeant 2 segments caractérisés par une direction.

    Si on est dans un de ces 2 segments en matchant la direction de ce dernier, j'applique la transformation de changement d’arête.
    J'ai donc pris le temps d'identifier manuellement les arêtes du jeu de test pour valider mon algo. Je me suis aidé d'un petit découpage papier
    pour faciliter l'opération.

    Puis, j'ai fait pareil pour mon jeu de données. C'est le plus long.

    Par exemple pour le Jeu de test, elle donne ceci.
    9,9->9,12L 8,8->5,8D
    5,5->8,5U 9,1->9,4L
    13,9->16,9U 12,8->12,5R
    1,5->4,5U 12,1->9,1U
    4,8->1,8D 9,12->12,12D
    13,12->16,12D 1,8->1,5L
    12,4->12,1R 16,9->16,12R

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import java.util.Scanner;
    
    
    
    public class A2022D22V2 {
    
    
        public static List<String> memory = new ArrayList<>();
        public static class Point  {
            int x;
            int y;
    
            public String toString() {
                return x + "," + y;
            }
        }
    
        public static class Segment {
            Point start;
            Point end;
            Direction direction;
    
            Segment(String part) {
                String[] points=  part.split("->");
                start = parsePoint(points[0]);
                end = parsePoint(points[1].substring(0, points[1].length()-1));
    
                char dir = points[1].charAt(points[1].length()-1);
                direction = Arrays.stream(Direction.values()).filter(a->a.name().charAt(0) == dir).findAny().orElse(null);
            }
    
            public Point parsePoint(String point) {
    
                String[] coords = point.split(",");
                Point p = new Point();
                p.x = Integer.valueOf(coords[0]);           
                p.x -= 1 ;
    
                p.y = Integer.valueOf(coords[1]);
                p.y -= 1;
    
                return p;
            }
    
            public String toString() {
                return start + " -> " + end + " " + direction;
            }
    
            public boolean include(int s, int v, int e) {
                if(s > e) {
                    int t = s;
                    s = e;
                    e = t;
                }
                return s <= v && v <= e;
            }
    
            public boolean include(A2022D22V2.Point p) {
                return include(start.x, p.x, end.x)
                        && include(start.y, p.y , end.y); 
            }
        }
    
        public static class Arrete {
            Segment a;      
            Segment b;
    
            public Arrete(String row) {
                String[] part = row.split(" ");
                a = new Segment(part[0]);
                b = new Segment(part[1]);           
            }       
    
            public String toString() {
                return a + " <=> " + b;
            }
    
            public static int normalize(int dx) {
                if(dx < 0 ) {
                    return -1;
                }
                if(dx == 0) {
                    return 0;
                }
                return 1;
            }
    
            public boolean moveTo(List<String> rowMap, A2022D22V2.Segment src, A2022D22V2.Segment dst, Monkey p) {
                int dx = normalize(src.end.x - src.start.x);
                int dy = normalize(src.end.y - src.start.y);
    
                int sx = src.start.x;
                int sy = src.start.y;
    
                int i = 0;
    
                while (sx != p.x || sy != p.y) {
                    sx += dx;
                    sy += dy;
                    i++;
                }
    
                dx = normalize(dst.end.x - dst.start.x);
                dy = normalize(dst.end.y - dst.start.y);
    
                sx = dst.start.x;
                sy = dst.start.y;
    
                while(i > 0) {
                    sx += dx;
                    sy += dy;
                    i--;                
                }
    
                System.out.println("Move:" + p.x + "," + p.y);
                System.out.println("====>" + sx + "," + sy);
                if(getChar(rowMap, sx ,sy) == '#') {
                    System.out.println("Blocked");
                    return false;
    
                }
                System.out.println("Ok!");
    
    
                p.x = sx;
                p.y = sy;
                p.direction = dst.direction.left().left();
    
                displayMap(p, true);
                return true;
            }
        }
    
        public enum Direction {
            RIGHT(1, 0, "UP", "DOWN",0),
            DOWN(0, 1, "RIGHT", "LEFT", 1),
            LEFT(-1,0, "DOWN", "UP", 2),
            UP(0, -1, "LEFT", "RIGHT", 3),
    
            ;
            int dx;
            int dy;
            int score;
    
            String rotateLeft;
            String rotateRight;
            private Direction(int dx, int dy, String rotateLeft,String rotateRight, int score) {
                this.dx = dx;
                this.dy = dy;
                this.rotateLeft = rotateLeft;
                this.rotateRight = rotateRight;
                this.score =score;
            };
    
            Direction left() {
                return Direction.valueOf(rotateLeft);
            }
    
            Direction right() {
                return Direction.valueOf(rotateRight);
            }
        }
    
    
        public static class Monkey extends Point{
    
    
            Direction direction = Direction.RIGHT;
    
        }
    
        public static void main(String[] args) {
            step1();
        }
    
        private static void step1() {
            List<String> rowMap = new ArrayList<>();
            String path = "";
            int maxWidth = 0;
            try (Scanner in = new Scanner(A2022D22V2.class.getResourceAsStream("/res/i22V2.txt"))) {            
                while (in.hasNext()) {
                    String row = in.nextLine();
                    if(row.isEmpty()) {
                        path = in.nextLine();
                    } else {
                        maxWidth = Math.max(maxWidth, row.length());
                        rowMap.add(row);
                    }
                }
            }
    
            List<Arrete> arretes = new ArrayList<>();
    
    
            try (Scanner in = new Scanner(A2022D22V2.class.getResourceAsStream("/res/i22V2rf.txt"))) {
                boolean parse = false;
                while (in.hasNext()) {
                    String row = in.nextLine().trim();
                    if("Parse".equals(row)) {
                        parse = true;
                    } else if(parse) {
                        System.out.println(row);
                        Arrete arrete  =new Arrete(row);
                        arretes.add(arrete);
                        System.out.println(arrete);
                    }
    
                }
            }
    
            normalizeMap(rowMap, maxWidth);
    
            Monkey monkey = new Monkey();
            monkey.x = rowMap.get(0).indexOf("."); 
            monkey.y = 0;
    
            System.out.println(path);
    
            int index = 0;
            while(index < path.length() && index >= 0) {
                if(path.charAt(index) == 'L') {
                    System.out.println("Left");
                    monkey.direction = monkey.direction.left();
                    index+=1;
                } else if(path.charAt(index) == 'R') {
                    System.out.println("Right");
                    monkey.direction = monkey.direction.right();
                    index+=1;
                } else {
    
                    int i = Integer.valueOf(path.substring(index).replaceAll("^([0-9]*).*", "$1"));
                    System.out.println("Move " + i);
                    index += (""+i).length();
                    do {                    
                        if(!translateToValid(rowMap, arretes, monkey))  {
                            break;
                        }                   
                        i--;
                        displayMap(monkey, false);
                    } while(i > 0);
    
                }
                displayMap(monkey, false);
            }
            displayMap(monkey, true);
            System.out.println(monkey.y+1);
            System.out.println(monkey.x+1);
            System.out.println(monkey.direction);
            int result = (monkey.y+1)*1000+(monkey.x+1)*4+monkey.direction.score;
            System.out.println(result);
        }
    
        private static void normalizeMap(List<String> rowMap, int maxWidth) {
    
            for(int y=0;y < rowMap.size();y++) {
                if(rowMap.get(y).length() < maxWidth) {
    
                    String row = rowMap.get(y);
                    while(row.length() < maxWidth) {
                        row += " ";
                    }
                    rowMap.set(y, row);
                }
                memory.add(new String(rowMap.get(y)));
            }
        }
    
        public static char getChar(List<String> rowMap, int sx, int sy) {
            String row = rowMap.get(sy);
            return row.charAt(sx);
        }
    
        private static boolean translateToValid(List<String> rowMap, List<Arrete> arretes, Monkey monkey) {     
            for(Arrete arrete: arretes) {           
                //System.out.println(arrete.a);
                if(arrete.a.include(monkey) && arrete.a.direction == monkey.direction) {
                    System.out.println(arrete.a + " " + monkey.direction);
                    return arrete.moveTo(rowMap, arrete.a, arrete.b, monkey);
    
    
                }
    
    
                if(arrete.b.include(monkey) && arrete.b.direction == monkey.direction) {
                    System.out.println(arrete.b + " " + monkey.direction);
                    return arrete.moveTo(rowMap, arrete.b, arrete.a, monkey);
    
                }
    
            }
    
            if(getChar(rowMap, monkey.x + monkey.direction.dx , monkey.y + monkey.direction.dy) == '#') {
                return false;
            }
    
            monkey.x += monkey.direction.dx;
            monkey.y += monkey.direction.dy;
            return true;
        }
    
        private static void displayMap(Monkey monkey, boolean print) {
            System.out.println();
            for(int y=0;y < memory.size();y++) {
                String row = memory.get(y);
                for(int x=0;x < row.length(); x++) {
                    if(monkey.x == x && monkey.y== y) {
                        char c;
                        switch (monkey.direction) {
                                case UP: 
                                    c = '^';
                                    break;                              
                                case DOWN: 
                                    c = 'u';
                                    break;                  
                                case RIGHT: 
                                    c = '>';
                                    break;                  
                                case LEFT: 
                                    c = '<';
                                    break;                      
                                default:
                                    throw new IllegalArgumentException("Unexpected value: " + monkey.direction);
                        }
                        if(print) System.out.print(c);
                        StringBuilder sb = new StringBuilder(row);
                        sb.setCharAt(x, c);
                        row = sb.toString();
                        memory.set(y, row);
                    } else {
                        if(print) System.out.print(row.charAt(x));
                    }
    
                }
                if(print) System.out.println();
            }
        }
    
    }
  • # Aujourd'hui, on fait dans le sale.

    Posté par  . En réponse au message Avent du Code, jour 21. Évalué à 2. Dernière modification le 21 décembre 2022 à 23:56.

    J'ai mis grosso modo 1h15.
    Pour faire l'éval, j'ai utilisé un parser JEXL. Le problème est qu'il travaille en double & qu'il m'a fallut passer en BigDecimal pour éviter les pertes de précisions du au double.
    Résultat, j'ai été obligé de transformer les expression pour utiliser des BigDecimal.
    çà m'a permit de trouver rapidement la première étoile.

    La deuxième étoile.
    J'ai déjà commencé par réduire l'arbre d'évaluation, en gros tout ce qui ne dépend pas de humn.

    Puis, j'ai rapidement vu que la fonction décroissé. J'aurai pu tenter une recherche dichotomique dans l'espace d'entier.
    Mais j'étais trop fatigué pour coder un truc intelligent.
    Résultat, j'ai monté une boucle qui permet de suivre l'évolution, j'ai joué manuellement sur les paramétres pour trouver la valeur

    C'est tellement sale que je partage mon code pour une fois :-p

    import java.math.BigDecimal;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    
    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 A2022D21S2 {
        private static final JexlEngine jexl = new JexlBuilder().cache(512).strict(true).silent(false).create();
    
        public static void main(String[] args) {                
            step1();
        }
    
        private static void step1() {
            Map<String, String> mapMonkey = new HashMap<>();
            try (Scanner in = new Scanner(A2022D21S2.class.getResourceAsStream("/res/i21.txt"))) {
    
                while (in.hasNext()) {
                    String row = in.nextLine();
                    String[] part = row.split(":");
                    if(part.length > 2) {
                        throw new RuntimeException();
                    }
                    if(part[0].equals( "root")) {
                        part[1] = part[1].replaceAll(" ", "").replaceAll("\\+", "-");
                        System.out.println("root:" + part[1]);
                    }
                    mapMonkey.put(part[0], part[1]);
                }
    
            }
    
            for (Map.Entry<String, String> entry : mapMonkey.entrySet()) {
                if (canReduce(mapMonkey, entry.getKey())) {
                    BigDecimal d = evalMonkey(mapMonkey, entry.getKey());
                    System.out.println("Reduce " + entry.getKey() + ":" + d.toPlainString());
                    mapMonkey.put(entry.getKey(), d.toPlainString());
                }
            }
    
            System.out.println("=========================");
    
            Double previous = null;
            for(long x=3876907167000L;x < 3876907168000L;x+= 1L) {
                BigDecimal bdx = new BigDecimal(x);
                mapMonkey.put("humn", bdx.toString());
                BigDecimal currentResult = evalMonkey(mapMonkey, "root");
                if(currentResult.doubleValue() == 0.0) {
                    System.out.println("Found:" + x);
                    break;
                }
                System.out.println(x + "=>" + currentResult.toPlainString());
                if(previous != null) {
                    System.out.println(previous > currentResult.doubleValue() ? "diminue" : "augmente");
                }
                previous = currentResult.doubleValue();
            }
        }
    
        private static boolean canReduce(Map<String, String> mapMonkey, String key) {
            String expr = mapMonkey.get(key);
            if(expr.matches("[ 0-9.]*")) {
                return true;
            }
    
            for(String other: mapMonkey.keySet()) {
    
                if(expr.contains(other)) {
                    if("root".equals(other) || "humn".equals(other)) {
                        return false;
                    } 
    
                    boolean r = canReduce(mapMonkey, other);
                    if(! r) {
                        return false;
                    }                           
                }
            }
            return true;
        }
    
        public static final BigDecimal MINUS_ONE = BigDecimal.valueOf(-1L);
        public static final BigDecimal ZERO = BigDecimal.valueOf(0L);
        public static final BigDecimal ONE = BigDecimal.valueOf(1L);
        private static BigDecimal evalMonkey(Map<String, String> mapMonkey, String name) {
            String expr = mapMonkey.get(name);
            if(expr.matches("[ 0-9.]*")) {
                return new BigDecimal(expr.replaceAll(" " , ""));
            }
    
            JexlContext context = new MapContext();
            context.set("MINUS_ONE", MINUS_ONE);
            for(String other: mapMonkey.keySet()) {
                if(expr.contains(other)) {
                    context.set(other, evalMonkey(mapMonkey, other));               
                }
            }
            expr = expr.replaceAll(" ", "");
            //System.out.println("Eval:" + expr);
            JexlExpression e = jexl.createExpression( expr );
    
            BigDecimal bdBigDecimal;
    
            expr = expr.replaceAll("\\+([a-z]*)", ".add($1)"); 
            expr = expr.replaceAll("\\*([a-z]*)", ".multiply($1)");
            expr = expr.replaceAll("\\/([a-z]*)", ".divide($1)");
            expr = expr.replaceAll("\\-([a-z]*)", ".add($1.mulitply(MINUS_ONE))");
    
            //System.out.println("Eval2:" + expr);
    
            Object o  =e.evaluate(context);
            if(o instanceof BigDecimal) {
                return (BigDecimal)o;
            }
    
            if(o instanceof Boolean) {
                return Boolean.TRUE.equals(o) ? ONE : ZERO;
            }
    
            throw new RuntimeException();
        }
    }
  • # il était vraiment null celui-ci

    Posté par  . En réponse au message Avent du Code, jour 20. Évalué à 2.

    J'ai pris le problème du mauvais sens, il m'a fallut plus de 3h pour comprendre qu'il ne fallait pas appliquer la transformation 3000 fois pour avoir la réponse.

    J'ai réecris 3 ou 4 fois mon code. J'ai commencé par un tableau avec des modulos au final, j'ai terminé par une liste doublement chainés comme quasiment tout le monde.

    J'ai remis une bonne 1h30 pour caler le modulo pour éviter d'appliquer les millions de déplacement.

    Bref, un très mauvaise journée. En plus, vous êtes plein à y être arrivé avant moins résultat.
    Je n'ai plus aucun espoir de rafler la seconde place.

  • [^] # Re: Modélisation trop longue à débugger

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

    Petite amélioration, je descends à 6s en modifiant mon DFS

    L'idée est de ne pas aller jusqu'au bout si on sait déjà qu'on sera en-dessous du meilleur temps.
    ```
    public static void executeDFS(State state) {
    int leftTurn = NB_TURN_32- state.index;
    int expGeode = state.geode+(NB_TURN_32-state.index) * (state.geodeRobot) + (leftTurn+1) * (leftTurn + 0) / 2;

    if(bestMap.get(state.bp) != null && expGeode < bestMap.get(state.bp)) {
    return;
    }

    if(state.index == NB_TURN_32) {
        if(bestMap.get(state.bp) == null || state.geode > bestMap.get(state.bp)) {              
            bestMap.put(state.bp, state.geode);                         
            System.out.println("Best:" + state.bp.index +";" + state.geode);                                            
        }
        return;
    }
    List<String> actions =state.availablesAction();
    State newState = new State(state.bp);
    for(String action : actions) {          
        state.copyInto(newState);
        newState.transform(action);
        executeDFS(newState);
    }
    

    }
    ```

  • [^] # Re: Modélisation trop longue à débugger

    Posté par  . En réponse au message Avent du Code, jour 19. Évalué à 2. Dernière modification le 19 décembre 2022 à 21:01.

    Au final, J'aurai mis 35min de plus.

    Le problème venait que j'avais mis une règle qui réduisait le nombre d'action possible pendant mon parcours en profondeur

    Il met 1min3s pour calculer le 2ème.

    Pour une fois , mon code n'est pas trop moche :)

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Random;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    public class A2022D19 {
        private static final String BUILD_ORE = "BUILD_ORE";
        private static final String BUILD_CLAY = "BUILD_CLAY";
        private static final String BUILD_OBSIDIAN = "BUILD_OBSIDIAN";
        private static final String BUILD_GEODE = "BUILD_GEODE";
        private static final String WAIT = "WAIT";
    
        static Map<BluePrint, Integer> bestMap = new HashMap<>();
    
        public static class Cost {
            int costOre;
            int costClay;
            int costObsidian;
    
            public String toString() {
                return costOre +";" + costClay + ";" + costObsidian;
            }                   
        }   
    
        public static class BluePrint {
            int index;
            Cost buildOreRobot;
            Cost buildClayRobot;
            Cost obsidianRobot; 
            Cost geodeRobot;
    
            public BluePrint(String row, int index) {
                this.index = index;
                String[] robots =  row.split("\\.");
    
                buildOreRobot = buildCost(robots[0]);
                buildClayRobot = buildCost(robots[1]);
                obsidianRobot = buildCost(robots[2]);
                geodeRobot = buildCost(robots[3]);
    
            }
    
            private Cost buildCost(String row) {
                Cost cost = new Cost();
                String regex;
                regex = ".* ([0-9]*) ore.*";
                if(row.matches(regex)) {
                    String s = row.replaceAll(regex, "$1");
                    cost.costOre = Integer.valueOf(s);
                }
    
    
                regex = ".* ([0-9]*) clay.*";
                if(row.matches(regex)) {
                    String s = row.replaceAll(regex, "$1");
                    cost.costClay = Integer.valueOf(s);
                }
    
                regex = ".* ([0-9]*) obsidian.*";
                if(row.matches(regex)) {
                    String s = row.replaceAll(regex, "$1");
                    cost.costObsidian = Integer.valueOf(s);
                }
    
                System.out.println(cost.toString());
    
                return cost;
            }
        }   
    
        public static class Action {
            int buildOreRobot = 0;
            int buildClayRobot = 0;
            int buildObsidianRobot = 0;
            int buildGeodeRobot = 0;
        }
    
        public static class State {
    
    
            BluePrint bp;
            int oreRobot = 1;
            int clayRobot = 0;
            int obsidianRobot = 0;
            int geodeRobot = 0;
    
            int ore = 0;
            int clay = 0;
            int obsidian = 0;
            int geode = 0;
            int index=0;
    
            public State(BluePrint bp) {
                this.bp = bp;
            }
    
            public boolean canPaid(Cost cost) {
                return ore >= cost.costOre
                    && clay >= cost.costClay
                    && obsidian >= cost.costObsidian;                                   
            }
    
            public void paid(Cost cost ) {
                ore -= cost.costOre;
                clay -= cost.costClay;
                obsidian -= cost.costObsidian;
            }
    
            public List<String> availablesAction() {
                List<String> actions  = new ArrayList<>();
                if(canPaid(bp.geodeRobot)) {                
                    actions.add(BUILD_GEODE);
                    return actions;
                }
    
                if(canPaid(bp.obsidianRobot)) {             
                    actions.add(BUILD_OBSIDIAN);
                    return actions;
                }
    
                if(canPaid(bp.buildClayRobot) && max(bp.buildOreRobot.costClay, bp.buildClayRobot.costClay, bp.obsidianRobot.costClay, bp.geodeRobot.costClay) >  this.clayRobot) {             
                    actions.add(BUILD_CLAY);                
                }
    
                if(canPaid(bp.buildOreRobot) && max(bp.buildOreRobot.costOre, bp.buildClayRobot.costOre, bp.obsidianRobot.costOre, bp.geodeRobot.costOre) >  this.oreRobot) {               
                    actions.add(BUILD_ORE);             
                }
    
                actions.add(WAIT);
                return actions;
    
            }
    
            private int max(int costOre, int costOre2, int costOre3, int costOre4) {
                return Math.max(Math.max(Math.max(costOre, costOre2), costOre3), costOre4);
            }
    
            public void transform(String command) {
                ++index;
                //System.out.println(index);
                //System.out.println(command);      
                this.ore += this.oreRobot;
                this.clay += this.clayRobot;
                this.obsidian += this.obsidianRobot;            
                this.geode += this.geodeRobot;      
    
                if(command.equals(BUILD_GEODE)) {
                    paid(bp.geodeRobot);
                    this.geodeRobot++;
                }
    
                if(command.equals(BUILD_OBSIDIAN)) {
                    paid(bp.obsidianRobot);
                    this.obsidianRobot++;
                }
    
                if(command.equals(BUILD_CLAY)) {
                    paid(bp.buildClayRobot);
                    this.clayRobot++;
                }
    
                if(command.equals(BUILD_ORE)) {
                    paid(bp.buildOreRobot);
                    this.oreRobot++;
                }
    
                //System.out.println("S:" + this.ore + ";"  + this.clay + ";" + this.obsidian + ";" + this.geode);
                //System.out.println("R:" + this.oreRobot + ";"  + this.clayRobot + ";" + this.obsidianRobot + ";" + this.geodeRobot);
    
            }
    
            public void copyInto(A2022D19.State newState) {
                newState.bp = this.bp;
                newState.oreRobot = this.oreRobot;
                newState.clayRobot = this.clayRobot;
                newState.obsidianRobot = this.obsidianRobot;
                newState.geodeRobot = this.geodeRobot;
    
                newState.ore = this.ore;
                newState.clay = this.clay;
                newState.obsidian = this.obsidian;
                newState.geode = this.geode;
                newState.index= this.index;
    
            }
        }
    
        public static void main(String[] args) {
            step1();
        }
    
    
        public static void executeDFS(State state) {
            if(state.index == 32) {
                if(bestMap.get(state.bp) == null || state.geode > bestMap.get(state.bp)) {              
                    bestMap.put(state.bp, state.geode);                         
                    System.out.println("Best:" + state.bp.index +";" + state.geode);                                            
                }
                return;
            }
            List<String> actions =state.availablesAction();
            State newState = new State(state.bp);
            for(String action : actions) {          
                state.copyInto(newState);
                newState.transform(action);
                executeDFS(newState);
            }
        }
    
        private static void step1() {
            try (Scanner in = new Scanner(A2022D19.class.getResourceAsStream("/res/i19.txt"))) {
                List<BluePrint> listBp = new ArrayList<>(); 
                while (in.hasNext()) {
                    String row = in.nextLine();
                    BluePrint bp = new BluePrint(row, listBp.size()+1);             
                    listBp.add(bp);
    
                }
    
                State state;    
                for(BluePrint bp: listBp) {
                    state =new State(bp);
                    executeDFS(state);
                }               
    
                int sum  = 0;
                int prod = 1;
                for(Map.Entry<BluePrint, Integer> e : bestMap.entrySet()) {
                    System.out.println("Final:" + e.getKey().index + "," + e.getValue());   
                    prod *= e.getValue();
                    sum += (e.getKey().index  * e.getValue());
                }
    
                System.out.println(sum);
                System.out.println(prod);
    
    
            }
    
        }
    
    }