123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- package main
- import (
- "fmt"
- "log"
- "os"
- )
- func getDiskMap(data []byte) []int {
- diskMap := make([]int, len(data))
- for i, block := range data {
- if block < 48 || block > 57 {
- continue
- }
- diskMap[i] = int(block) - 48
- }
- return diskMap
- }
- func getDisk(diskMap []int) (int, []int) {
- var disk []int
- file := true
- var fileID int
- for _, number := range diskMap {
- if file {
- file = false
- for j := 0; j < number; j++ {
- disk = append(disk, fileID)
- }
- fileID++
- } else {
- file = true
- for j := 0; j < number; j++ {
- disk = append(disk, -1)
- }
- }
- }
- return diskMap[0], disk
- }
- func compact(disk []int, free int) []int {
- end := len(disk) - 1
- for free < end {
- if disk[free] != -1 {
- free++
- continue
- }
- if disk[end] == -1 {
- end--
- continue
- }
- disk[free], disk[end] = disk[end], disk[free]
- free++
- end--
- }
- return disk
- }
- func calculateChecksum(disk []int) int64 {
- var checksum int64
- for i := range disk {
- if disk[i] != -1 {
- checksum += int64(disk[i] * i)
- }
- }
- return checksum
- }
- func part1(diskMap []int) int64 {
- free, disk := getDisk(diskMap)
- compacted := compact(disk, free)
- return calculateChecksum(compacted)
- }
- func findFile(disk []int, id, end int) int {
- for i := end; i > 0; i-- {
- if disk[i] != id {
- return i + 1
- }
- }
- return -1
- }
- func findFree(disk []int, start, end, goal int) (int, int) {
- var freeStart, freeEnd int
- for i := start; i < end; i++ {
- if disk[i] == -1 {
- if freeStart <= 0 {
- freeStart = i
- for j := freeStart + 1; j < freeStart+goal; j++ {
- if disk[j] != -1 {
- freeStart = -1
- i = j
- break
- }
- }
- if freeStart > 0 {
- return freeStart, freeStart + goal
- }
- }
- }
- }
- return freeStart, freeEnd
- }
- func defrag(diskMap []int) []int {
- free, disk := getDisk(diskMap)
- end := len(disk) - 1
- for i := end; i > free; i-- {
- if disk[i] > 0 {
- fileStart := findFile(disk, disk[i], i)
- if fileStart > 0 {
- freeStart, freeEnd := findFree(disk, free, fileStart, i-fileStart+1)
- if freeStart > 0 && freeEnd > 0 && freeStart < freeEnd {
- for k := freeStart; k < freeEnd; k++ {
- disk[k] = disk[i]
- }
- for k := fileStart; k <= i; k++ {
- disk[k] = -1
- }
- }
- i = fileStart
- }
- }
- }
- return disk
- }
- func part2(diskMap []int) int64 {
- defragmented := defrag(diskMap)
- return calculateChecksum(defragmented)
- }
- func main() {
- if len(os.Args) < 2 {
- log.Fatal("You need to specify a file!")
- }
- data, err := os.ReadFile(os.Args[1])
- if err != nil {
- log.Fatal(err)
- }
- diskMap := getDiskMap(data)
- fmt.Println("Part1:", part1(diskMap))
- fmt.Println("Part2:", part2(diskMap))
- }
|