Selaa lähdekoodia

day12 works on example input

Aleksei Dorokhov 7 kuukautta sitten
vanhempi
commit
f58a1f3634
4 muutettua tiedostoa jossa 468 lisäystä ja 101 poistoa
  1. 105 0
      day12/area.zig
  2. 152 101
      day12/day12a.zig
  3. 101 0
      day12/input.zig
  4. 110 0
      day12/shape.zig

+ 105 - 0
day12/area.zig

@@ -0,0 +1,105 @@
+const std = @import("std");
+
+const shapeModule = @import("shape.zig");
+const Shape = shapeModule.Shape;
+const kShapeSize = shapeModule.kShapeSize;
+
+pub const Area = struct {
+    rows: u8 = 0,
+    cols: u8 = 0,
+    data: []u8 = undefined,
+    dataAllocator: std.mem.Allocator,
+
+    pub fn init(allocator: std.mem.Allocator, rows: u8, cols: u8) !Area {
+        var area: Area = .{
+            .rows = rows,
+            .cols = cols,
+            .data = try allocator.alloc(u8, rows*cols),
+            .dataAllocator = allocator,
+        };
+
+        for (0 .. area.data.len) |i| {
+            area.data[i] = '.';
+        }
+        return area;
+    }
+
+    pub fn deinit(self: *const Area) void {
+        self.dataAllocator.free(self.data);
+    }
+
+    pub fn copy(self: *const Area, allocator: std.mem.Allocator) !Area {
+        const area: Area = .{
+            .rows = self.rows,
+            .cols = self.cols,
+            .data = try allocator.alloc(u8, self.rows*self.cols),
+            .dataAllocator = allocator,
+        };
+        std.mem.copyForwards(u8, area.data, self.data);
+        return area;
+    }
+
+    pub fn totalFreeSize(self: *const Area) usize {
+        var freeSize:usize = 0;
+        for (self.data) |d| {
+            if (d == '.') {
+                freeSize += 1;
+            }
+        }
+        return freeSize;
+    }
+
+    pub fn getCell(self: *const Area, row: u8, col: u8) u8 {
+        return self.data[row*self.cols + col];
+    }
+
+    pub fn setCell(self: *Area, row: u8, col: u8, cell: u8) void {
+        self.data[row*self.cols + col] = cell;
+    }
+
+    pub fn print(self: *const Area, allocator: std.mem.Allocator) !void {
+        for (0..self.rows) |row| {
+            for (0..self.cols) |col| {
+                const cell = self.getCell(@intCast(row), @intCast(col));
+                try std.fs.File.stdout().writeAll(
+                  try std.fmt.allocPrint(allocator, "{c}", .{cell}));
+        
+            }
+            try std.fs.File.stdout().writeAll("\n");
+        }
+    }
+
+    pub fn appendShape(self: * const Area, allocator: std.mem.Allocator,
+                       shape: *const Shape, row: u8, col: u8, shapeSymbol: u8) !?Area {
+        var area = try self.copy(allocator);
+        for (0..kShapeSize) |shapeRow| {
+            for (0..kShapeSize) |shapeCol| {
+                if (shape.getCell(@intCast(shapeRow), @intCast(shapeCol)) == '.') {
+                    continue;
+                }
+
+                const areaRow:u8 = @intCast(shapeRow + row);
+                if (areaRow >= area.rows) {
+                    area.deinit();
+                    return null;
+                }
+
+                const areaCol:u8 = @intCast(shapeCol + col);
+                if (areaCol >= area.cols) {
+                    area.deinit();
+                    return null;
+                }
+
+                if (area.getCell(areaRow, areaCol) != '.') {
+                    area.deinit();
+                    return null;
+                }
+
+                area.setCell(areaRow, areaCol, shapeSymbol);
+            }
+        }
+
+        return area;
+    }
+};
+

+ 152 - 101
day12/day12a.zig

@@ -1,119 +1,149 @@
 const std = @import("std");
 
-var allocatorBuffer: [100*1024*1024]u8 = undefined;
-
-const Shape = struct {
-    data: [9]u8,
+const shapeModule = @import("shape.zig");
+const inputModule = @import("input.zig");
+const areaModule = @import("area.zig");
+
+const Shape = shapeModule.Shape;
+const Area = areaModule.Area;
+const kShapeSize = shapeModule.kShapeSize;
+const readInputIntoString = inputModule.readInputIntoString;
+const parseInput = inputModule.parseInput;
+
+const Coord = struct {
+    row: u8,
+    col: u8,
+};
 
-    fn getCell(self: *const Shape, row: u8, col: u8) u8 {
-        return self.data[row*3 + col];
+pub fn getEligibleCoords(allocator: std.mem.Allocator,
+                         area: Area,
+                         eligibleCoords: *std.ArrayList(Coord)) !void {
+    eligibleCoords.clearRetainingCapacity();
+
+    for (0 .. area.rows) |row| {
+        for (0 .. area.cols) |col|  {
+            if (area.getCell(@intCast(row), @intCast(col)) == '.') {
+                var shouldAdd = false;
+                if (row > 0 and area.getCell(@intCast(row-1), @intCast(col)) != '.') {
+                    shouldAdd = true;
+                } else if (col > 0 and area.getCell(@intCast(row), @intCast(col-1)) != '.') {
+                    shouldAdd = true;
+                } else if (row < area.rows - 1 and area.getCell(@intCast(row+1), @intCast(col)) != '.') {
+                    shouldAdd = true;
+                } else if (col < area.cols - 1 and area.getCell(@intCast(row), @intCast(col+1)) != '.') {
+                    shouldAdd = true;
+                }
+
+                if (shouldAdd) {
+                    var newEligibleCoord = try eligibleCoords.addOne(allocator);
+                    newEligibleCoord.row = @intCast(row);
+                    newEligibleCoord.col = @intCast(col);
+                }
+            }
+        }
     }
 
-    fn setCell(self: *Shape, row: u8, col: u8, cell: u8) void {
-        self.data[row*3 + col] = cell;
+    if (eligibleCoords.items.len == 0 and area.getCell(0, 0) == '.') {
+        var newEligibleCoord = try eligibleCoords.addOne(allocator);
+        newEligibleCoord.row = 0;
+        newEligibleCoord.col = 0;
     }
-};
-
-const Area = struct {
-    rows: u8,
-    cols: u8,
-    shapesCount: []u8,
-};
-
-const Input = struct {
-    shapes: []Shape,
-    areas: []Area,
-};
+}
 
-pub fn parseShape(shapeText: []const u8) Shape {
-    var it = std.mem.tokenizeScalar(u8, shapeText, '\n');
-    _ = it.next(); // skip header
-    
-    var shape: Shape = .{
-        .data = undefined,
-    };
-    
-    for (0..3) |row| {
-        const rowText = it.next().?;
-        for (0..3) |col| {
-            shape.setCell(@intCast(row), @intCast(col), rowText[col]);
+pub fn calculateShapeSizes(allocator: std.mem.Allocator, shapeTransforms: []const []const Shape) ![]usize{
+    var shapeSizes = try allocator.alloc(usize, shapeTransforms.len);
+    for (0..shapeTransforms.len) |i| {
+        shapeSizes[i] = 0;
+        for (shapeTransforms[i][0].data) |d| {
+            if (d != '.') {
+                shapeSizes[i] += 1;
+            }
         }
     }
-
-    return shape;
+    return shapeSizes;
 }
 
-pub fn parseArea(allocator: std.mem.Allocator, line: []const u8) !Area {
-    var it = std.mem.tokenizeSequence(u8, line, ": ");
-    const sizeText = it.next().?;
-    const shapesCountText = it.next().?;
+pub fn calcShapesTotalSize(shapeCounts: []u8, shapeSizes: []usize) usize {
+    var totalSize: usize = 0;
 
-    var sizeTextIt = std.mem.tokenizeScalar(u8, sizeText, 'x');
-    const rowsText = sizeTextIt.next().?;
-    const colsText = sizeTextIt.next().?;
+    for (0..shapeCounts.len) |i| {
+        totalSize += shapeSizes[i] * shapeCounts[i];
+    }
+    return totalSize;
+}
 
-    const rows = try std.fmt.parseInt(u8, rowsText, 10);
-    const cols = try std.fmt.parseInt(u8, colsText, 10);
 
-    var shapesCountTextIt = std.mem.tokenizeScalar(u8, shapesCountText, ' ');
-    var shapesCount = std.ArrayList(u8).empty;
-    while (shapesCountTextIt.next()) |shapeCountText| {
-      const shapeCount = try shapesCount.addOne(allocator);
-      shapeCount.* = try std.fmt.parseInt(u8, shapeCountText, 10);
+pub fn canContainShapes(allocator: std.mem.Allocator, area: Area,
+                        shapeCounts: []u8, shapeTransforms: []const []const Shape,
+                        shapeSizes: []usize) !bool {
+    // try std.fs.File.stdout().writeAll("canContainShapes: [");
+    // for (shapeCounts) |shapeCount| {
+    //     try std.fs.File.stdout().writeAll(
+    //       try std.fmt.allocPrint(allocator, " {d} ", .{shapeCount}));
+    // }
+    // try std.fs.File.stdout().writeAll("]\n");
+
+    if (calcShapesTotalSize(shapeCounts, shapeSizes) > area.totalFreeSize()) {
+        return false;
     }
+
+    var eligibleCoords = std.ArrayList(Coord).empty;
+    defer eligibleCoords.deinit(allocator);
     
-    const area: Area = .{
-        .rows = rows,
-        .cols = cols,
-        .shapesCount = shapesCount.items,
-    };
+    var allEmpty = true;
+    for (shapeCounts) |shapeCount| {
+        if (shapeCount != 0) {
+            allEmpty = false;
+            break;
+        }
+    }
+    if (allEmpty) {
+        try area.print(allocator);
+        return true;
+    }
 
-    return area;
-}
+    for (0 .. shapeCounts.len) |shapeIndex| {
+        if (shapeCounts[shapeIndex] == 0) {
+            continue;
+        }
 
-pub fn parseInput(allocator: std.mem.Allocator, inputBuffer: []u8) !Input {
-    var shapes = std.ArrayList(Shape).empty;
-    var areas = std.ArrayList(Area).empty;
-
-    var i = std.mem.tokenizeSequence(u8, inputBuffer, "\n\n");
-    while (i.next()) |inputBlock| {
-        if (inputBlock.len >= 2 and inputBlock[1] == ':') {
-            const shape = try shapes.addOne(allocator);
-            shape.* = parseShape(inputBlock);
-        } else {
-            var it = std.mem.tokenizeScalar(u8, inputBlock, '\n');
-            while(it.next()) |line| {
-                const area = try areas.addOne(allocator);
-                area.* = try parseArea(allocator, line);
+        for (0..shapeTransforms[shapeIndex].len) |shapeVariant| {
+            try getEligibleCoords(allocator, area, &eligibleCoords);
+
+            for (eligibleCoords.items) |coord| {
+                const row = coord.row;
+                const col = coord.col;
+
+                if (try area.appendShape(
+                      allocator,
+                      &shapeTransforms[shapeIndex][shapeVariant],
+                      @intCast(row), @intCast(col), '#')) |newArea| {
+                    defer newArea.deinit();
+
+                    // try std.fs.File.stdout().writeAll("Step: \n");
+                    // try newArea.print(allocator);
+                    // try std.fs.File.stdout().writeAll("\n");
+
+                    var newShapeCounts = try allocator.alloc(u8, shapeCounts.len);
+                    defer allocator.free(newShapeCounts);
+                    std.mem.copyForwards(u8, newShapeCounts, shapeCounts);
+                    newShapeCounts[shapeIndex] -= 1;
+
+                    if (try canContainShapes(allocator, newArea, newShapeCounts,
+                                             shapeTransforms, shapeSizes)) {
+                        return true;
+                    }
+                }
             }
         }
     }
 
-    const input: Input = .{
-        .shapes = shapes.items,
-        .areas = areas.items,
-    };
-
-    return input;
-}
-
-pub fn readInputIntoString(allocator: std.mem.Allocator, fileName: []const u8) ![]u8 {
-    const inputFile = try std.fs.cwd().openFile(
-        fileName, .{.mode = .read_only,});
-    defer inputFile.close();
-
-    var inputFileReader = inputFile.reader(
-      try allocator.alignedAlloc(u8, null, 1024));
-    const inputFileSize = try inputFileReader.getSize();
-
-    const inputBuffer = try allocator.alignedAlloc(u8, null, inputFileSize);
-    try inputFileReader.interface.readSliceAll(inputBuffer);
-    return inputBuffer;
+    return false;
 }
 
 pub fn main() !void {
-    var fb_alloc = std.heap.FixedBufferAllocator.init(&allocatorBuffer);
-    const allocator = fb_alloc.allocator();
+    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+    const allocator = gpa.allocator();
 
     const inputBuffer = try readInputIntoString(allocator, "input.txt");
     const input = try parseInput(allocator, inputBuffer);
@@ -128,18 +158,39 @@ pub fn main() !void {
          try std.fs.File.stdout().writeAll("]\n");
     }
 
-    for (input.shapes) |shape| {
-        try std.fs.File.stdout().writeAll("shape:\n");
-        for (0..3) |row| {
-            for (0..3) |col| {
-                const cell = shape.getCell(@intCast(row), @intCast(col));
-                try std.fs.File.stdout().writeAll(
-                  try std.fmt.allocPrint(allocator, "{c}", .{cell}));
+    var shapeTransforms: [][]Shape = try allocator.alloc([]Shape, input.shapes.len);
+    for (0..input.shapes.len) |i| {
+        var allTransforms = try input.shapes[i].getAllTransforms(allocator);
+        defer allTransforms.deinit();
 
-            }
-            try std.fs.File.stdout().writeAll("\n");
+        shapeTransforms[i] = try allocator.alloc(Shape, allTransforms.count());
+
+        var j: usize = 0;
+        var it = allTransforms.keyIterator();
+        while (it.next()) |shapeTransform| {
+            shapeTransforms[i][j] = shapeTransform.*;
+            j += 1;
+        }
+    }
+
+    const shapeSizes = try calculateShapeSizes(allocator, shapeTransforms);
+    defer allocator.free(shapeSizes);
+
+    var counter: usize = 0;
+    for (0..input.areas.len) |i| {
+        const area = try Area.init(allocator, input.areas[i].rows, input.areas[i].cols);
+        defer area.deinit();
+        
+        if(try canContainShapes(allocator, area, input.areas[i].shapesCount, shapeTransforms, shapeSizes)) {
+            try std.fs.File.stdout().writeAll("Can contain shapes!\n");
+            counter += 1;
+        }
+        else {
+            try std.fs.File.stdout().writeAll("Can NOT contain shapes!\n");
         }
-        try std.fs.File.stdout().writeAll("\n");
     }
+
+    try std.fs.File.stdout().writeAll(
+      try std.fmt.allocPrint(allocator, "Answer: {d}\n", .{counter}));
 }
 

+ 101 - 0
day12/input.zig

@@ -0,0 +1,101 @@
+const std = @import("std");
+const shapeModule = @import("shape.zig");
+const Shape = shapeModule.Shape;
+
+pub const AreaRequirements = struct {
+    rows: u8,
+    cols: u8,
+    shapesCount: []u8,
+};
+
+pub const Input = struct {
+    shapes: []Shape,
+    areas: []AreaRequirements,
+};
+
+fn parseShape(shapeText: []const u8) Shape {
+    var it = std.mem.tokenizeScalar(u8, shapeText, '\n');
+    _ = it.next(); // skip header
+    
+    var shape: Shape = .{
+        .data = undefined,
+    };
+    
+    for (0..3) |row| {
+        const rowText = it.next().?;
+        for (0..3) |col| {
+            shape.setCell(@intCast(row), @intCast(col), rowText[col]);
+        }
+    }
+
+    return shape;
+}
+
+fn parseAreaRequirements(allocator: std.mem.Allocator, line: []const u8) !AreaRequirements {
+    var it = std.mem.tokenizeSequence(u8, line, ": ");
+    const sizeText = it.next().?;
+    const shapesCountText = it.next().?;
+
+    var sizeTextIt = std.mem.tokenizeScalar(u8, sizeText, 'x');
+    const rowsText = sizeTextIt.next().?;
+    const colsText = sizeTextIt.next().?;
+
+    const rows = try std.fmt.parseInt(u8, rowsText, 10);
+    const cols = try std.fmt.parseInt(u8, colsText, 10);
+
+    var shapesCountTextIt = std.mem.tokenizeScalar(u8, shapesCountText, ' ');
+    var shapesCount = std.ArrayList(u8).empty;
+    while (shapesCountTextIt.next()) |shapeCountText| {
+      const shapeCount = try shapesCount.addOne(allocator);
+      shapeCount.* = try std.fmt.parseInt(u8, shapeCountText, 10);
+    }
+    
+    const area: AreaRequirements = .{
+        .rows = rows,
+        .cols = cols,
+        .shapesCount = shapesCount.items,
+    };
+
+    return area;
+}
+
+pub fn parseInput(allocator: std.mem.Allocator, inputBuffer: []u8) !Input {
+    var shapes = std.ArrayList(Shape).empty;
+    var areas = std.ArrayList(AreaRequirements).empty;
+
+    var i = std.mem.tokenizeSequence(u8, inputBuffer, "\n\n");
+    while (i.next()) |inputBlock| {
+        if (inputBlock.len >= 2 and inputBlock[1] == ':') {
+            const shape = try shapes.addOne(allocator);
+            shape.* = parseShape(inputBlock);
+        } else {
+            var it = std.mem.tokenizeScalar(u8, inputBlock, '\n');
+            while(it.next()) |line| {
+                const area = try areas.addOne(allocator);
+                area.* = try parseAreaRequirements(allocator, line);
+            }
+        }
+    }
+
+    const input: Input = .{
+        .shapes = shapes.items,
+        .areas = areas.items,
+    };
+
+    return input;
+}
+
+pub fn readInputIntoString(allocator: std.mem.Allocator, fileName: []const u8) ![]u8 {
+    const inputFile = try std.fs.cwd().openFile(
+        fileName, .{.mode = .read_only,});
+    defer inputFile.close();
+
+    var inputFileReader = inputFile.reader(
+      try allocator.alignedAlloc(u8, null, 1024));
+    const inputFileSize = try inputFileReader.getSize();
+
+    const inputBuffer = try allocator.alignedAlloc(u8, null, inputFileSize);
+    try inputFileReader.interface.readSliceAll(inputBuffer);
+    return inputBuffer;
+}
+

+ 110 - 0
day12/shape.zig

@@ -0,0 +1,110 @@
+const std = @import("std");
+
+pub const kShapeSize: u8 = 3;
+
+pub const Shape = struct {
+    data: [9]u8,
+
+    pub fn getCell(self: *const Shape, row: u8, col: u8) u8 {
+        return self.data[row*kShapeSize + col];
+    }
+
+    pub fn setCell(self: *Shape, row: u8, col: u8, cell: u8) void {
+        self.data[row*kShapeSize + col] = cell;
+    }
+
+    pub fn flipHor(self: *Shape) void {
+        for (0 .. kShapeSize) |row| {
+            for (0 .. kShapeSize/2) |col| {
+                const t = self.getCell(@intCast(row), @intCast(col));
+                self.setCell(@intCast(row), @intCast(col), 
+                             self.getCell(@intCast(row),
+                                          @intCast(kShapeSize - 1 - col)));
+                self.setCell(@intCast(row), @intCast(kShapeSize - 1 - col), t);
+            }
+        }
+    }
+
+    pub fn flipVer(self: *Shape) void {
+        for (0 .. kShapeSize) |col| {
+            for (0 .. kShapeSize/2) |row| {
+                const t = self.getCell(@intCast(row), @intCast(col));
+                self.setCell(@intCast(row), @intCast(col), 
+                             self.getCell(@intCast(kShapeSize - 1 - row),
+                                          @intCast(col)));
+                self.setCell(@intCast(kShapeSize - 1 - row), @intCast(col), t);
+            }
+        }
+    }
+
+
+    pub fn rotate(self: *Shape) void {
+        for (0 .. kShapeSize-1) |row| {
+            for (row+1 .. kShapeSize) |col| {
+                const t = self.getCell(@intCast(row), @intCast(col));
+                self.setCell(@intCast(row), @intCast(col),
+                             self.getCell(@intCast(col), @intCast(row)));
+                self.setCell(@intCast(col), @intCast(row), t);
+            }
+        }
+
+        self.flipHor();
+    }
+
+    pub fn getAllTransforms(self: * const Shape, allocator: std.mem.Allocator) !std.AutoHashMap(Shape, bool) {
+        var allTransforms = std.AutoHashMap(Shape, bool).init(allocator);
+
+        try allTransforms.put(self.*, true);
+
+
+        var shapeHFlip = self.*;
+        shapeHFlip.flipHor();
+
+        for (0 .. 4) |_| {
+            try allTransforms.put(shapeHFlip, true);
+            shapeHFlip.rotate();
+        }
+
+        var shapeVFlip = self.*;
+        shapeVFlip.flipVer();
+
+        for (0 .. 4) |_| {
+            try allTransforms.put(shapeVFlip, true);
+            shapeVFlip.rotate();
+        }
+
+
+        var shapeHVFlip = self.*;
+        shapeHVFlip.flipHor();
+        shapeHVFlip.flipVer();
+
+        for (0 .. 4) |_| {
+            try allTransforms.put(shapeHVFlip, true);
+            shapeHVFlip.rotate();
+        }
+
+        var shapeVHFlip = self.*;
+        shapeVHFlip.flipVer();
+        shapeVHFlip.flipHor();
+
+        for (0 .. 4) |_| {
+            try allTransforms.put(shapeVHFlip, true);
+            shapeVHFlip.rotate();
+        }
+
+        return allTransforms;
+    }
+
+    pub fn print(self: *const Shape, allocator: std.mem.Allocator) !void {
+        for (0..kShapeSize) |row| {
+            for (0..kShapeSize) |col| {
+                const cell = self.getCell(@intCast(row), @intCast(col));
+                try std.fs.File.stdout().writeAll(
+                  try std.fmt.allocPrint(allocator, "{c}", .{cell}));
+        
+            }
+            try std.fs.File.stdout().writeAll("\n");
+        }
+    }
+};
+