import java.io.File class Pattern(val size: Int){ val map = Array(size) { CharArray(size) { ' ' } } fun flipV(): Pattern { val newPattern = Pattern(size) for(x in 0 until size){ for(y in 0 until size){ val newX = size - 1 - x val newY = y newPattern.map[newY][newX] = map[y][x] } } return newPattern } fun flipH(): Pattern { val newPattern = Pattern(size) for(x in 0 until size){ for(y in 0 until size){ val newX = x val newY = size - 1 - y newPattern.map[newY][newX] = map[y][x] } } return newPattern } fun rotate(): Pattern { val newPattern = Pattern(size) for(x in 0 until size){ for(y in 0 until size){ val newX = y val newY = size - 1 - x newPattern.map[newY][newX] = map[y][x] } } return newPattern } override operator fun equals(other: Any?): Boolean { if(other !is Pattern) return false return oneEquals(other) } fun equalsPattern(other: Pattern): Boolean { if(other.size != size) return false for(x in 0 until size) { for(y in 0 until size){ if(other.map[y][x] != this.map[y][x]) return false } } return true } fun oneEquals(other: Pattern): Boolean { val first = rotate() val flipH = flipH() val flipV = flipV() val thisMatches = equalsPattern(other) || rotate().equalsPattern(other) || rotate().rotate().equalsPattern(other) || rotate().rotate().rotate().equalsPattern(other) val flipHMatches = flipH.equalsPattern(other) || flipH.rotate().equalsPattern(other) || flipH.rotate().rotate().equalsPattern(other) || flipH.rotate().rotate().rotate().equalsPattern(other) val flipVMatches = flipV.equalsPattern(other) || flipV.rotate().equalsPattern(other) || flipV.rotate().rotate().equalsPattern(other) || flipV.rotate().rotate().equalsPattern(other) return thisMatches || flipHMatches || flipVMatches } fun toStrings(): List{ return map.map { it.joinToString(" ") } } fun split(): List> { val toReturn = mutableListOf>() if(size % 2 == 0){ for(y in 0 until size / 2){ val newRow = mutableListOf() for(x in 0 until size / 2){ val newPattern = Pattern(2) for(newX in 0..1){ for(newY in 0..1){ newPattern.map[newY][newX] = map[y * 2 + newY][x * 2 + newX] } } newRow.add(newPattern) } toReturn.add(newRow) } } else { for(y in 0 until size / 3){ val newRow = mutableListOf() for(x in 0 until size / 3){ val newPattern = Pattern(3) for(newX in 0..2){ for(newY in 0..2){ newPattern.map[newY][newX] = map[y * 3 + newY][x * 3 + newX] } } newRow.add(newPattern) } toReturn.add(newRow) } } return toReturn } } fun fromString(s: String): Pattern { val lines = s.split("/") val newPattern = Pattern(lines.size) for(i in 0 until newPattern.size){ newPattern.map[i] = lines[i].toCharArray() } return newPattern } fun combine(list: List>): Pattern { val newPattern = Pattern(list[0][0].size * list.size) for(y in 0 until list.size){ for(x in 0 until list.size){ val copying = list[y][x] for(oldY in 0 until copying.size){ for(oldX in 0 until copying.size){ newPattern.map[y * copying.size + oldY][x * copying.size + oldX] = copying.map[oldY][oldX] } } } } return newPattern } fun Map.findMatching(pattern: Pattern): Pattern? { return keys .firstOrNull { it == pattern } ?.let { get(it) } } fun main(args: Array){ // val file = File("test.txt") val file = File("../puzzle_21.txt") val lines = file.readLines() val patternMap = mutableMapOf() lines.forEach { val split = it.split(" => ") patternMap.put(fromString(split[0]), fromString(split[1])) } val inputPattern = fromString(".#./..#/###") var pattern = inputPattern var count = 0 while (count < 18){ val split = pattern.split() pattern = combine(split.map { it.map { patternMap.findMatching(it)!! } }) pattern.toStrings().forEach { println(it) } println() count += 1 } println(pattern.toStrings().joinToString("").count { it == '#' }) }