diff --git a/day9/main.go b/day9/main.go
index c6427e7..848e319 100644
--- a/day9/main.go
+++ b/day9/main.go
@@ -39,6 +39,7 @@ func printDiskBlocks(diskBlocks []int) {
 			fmt.Printf("%d", b)
 		}
 	}
+	fmt.Println()
 }
 
 func compact(in []int) []int {
@@ -60,7 +61,7 @@ func compact(in []int) []int {
 	return out
 }
 
-func checksum(diskBlocks []int) int {
+func calculateChecksum(diskBlocks []int) int {
 	var checksum = 0
 	for i, b := range diskBlocks {
 		if b != FREE {
@@ -70,21 +71,90 @@ func checksum(diskBlocks []int) int {
 	return checksum
 }
 
+func findFreeSpace(blocks []int, size int) int {
+	var targetBegin, foundSize int
+	targetBegin = -1
+	for i := range blocks {
+		if blocks[i] == FREE && targetBegin == -1 {
+			targetBegin = i
+		}
+		if blocks[i] != FREE && targetBegin != -1 {
+			foundSize = i - targetBegin
+			if foundSize >= size {
+				return targetBegin
+			}
+			targetBegin = -1
+		}
+	}
+	return -1
+}
+
+func set(blocks []int, begin, end, fileId int) {
+	for i := begin; i <= end; i++ {
+		blocks[i] = fileId
+	}
+}
+
+func defrag(in []int) []int {
+	var out = make([]int, len(in))
+	copy(out[:], in[:])
+
+	var fileId, sourceBegin, sourceEnd int
+	fileId = -1
+	for i := len(in) - 1; i >= 0; i-- {
+		if fileId > 0 && fileId != in[i] {
+			// case 1: we've exited the file
+			var size, targetBegin int
+
+			sourceBegin = i + 1
+			size = sourceEnd - sourceBegin + 1
+
+			targetBegin = findFreeSpace(out, size)
+			if targetBegin >= 0 && targetBegin < sourceBegin {
+				fmt.Printf("  move: %d -> %d (size %d)\n", sourceBegin, targetBegin, size)
+				set(out, sourceBegin, sourceEnd, FREE)
+				set(out, targetBegin, targetBegin+size-1, fileId)
+			} else {
+				fmt.Printf("  stay: %d (size %d)\n", sourceBegin, size)
+			}
+			fileId = -1
+		}
+		if fileId < 0 {
+			if in[i] == FREE {
+				// case 2: we're crossing void areas
+				continue
+			}
+			// case 3: we're entering the file
+			fileId = in[i]
+			sourceEnd = i
+		}
+	}
+	return out
+}
+
 func main() {
 	scanner := bufio.NewScanner(os.Stdin)
 	scanner.Split(bufio.ScanLines)
 
+	var diskMap string
 	scanner.Scan()
-	var diskMap = scanner.Text()
+	diskMap = scanner.Text()
 
-	var diskBlocks = calculateDiskBlocks(diskMap)
+	var diskBlocks []int
+	diskBlocks = calculateDiskBlocks(diskMap)
 	printDiskBlocks(diskBlocks)
-	fmt.Println()
 
-	diskBlocks = compact(diskBlocks)
-	printDiskBlocks(diskBlocks)
-	fmt.Println()
+	var compactDiskBlocks []int
+	var compactChecksum int
+	compactDiskBlocks = compact(diskBlocks)
+	printDiskBlocks(compactDiskBlocks)
+	compactChecksum = calculateChecksum(compactDiskBlocks)
+	fmt.Printf("compact checksum: %d\n", compactChecksum)
 
-	var checksum = checksum(diskBlocks)
-	fmt.Printf("checksum: %d\n", checksum)
+	var defragDiskBlocks []int
+	var defragChecksum int
+	defragDiskBlocks = defrag(diskBlocks)
+	printDiskBlocks(defragDiskBlocks)
+	defragChecksum = calculateChecksum(defragDiskBlocks)
+	fmt.Printf("defrag checksum: %d\n", defragChecksum)
 }