• # 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];
    }