import std/[algorithm, math] import lib/loader type BinSet = object start: int stop: int Half = enum hLow, hHigh Seat = object row: int col: int proc newBinSet(size: int): BinSet = # check to make sure size is a power of 2 var q = size while q mod 2 == 0: q = q div 2 if q != 1: raise newException(ValueError, "BinSet must have a size that is a power of 2.") result = BinSet(start: 0, stop: size - 1) proc size(bs: BinSet): int = bs.stop - bs.start + 1 # bounds are inclusive func seatId(s: Seat): int = s.row * 8 + s.col func seatCmp(s1, s2: Seat): int = let i1 = s1.seatId() let i2 = s2.seatId() if i1 < i2: return -1 elif i1 == i2: return 0 else: return 1 proc split(bs: var BinSet, h: Half) = if h == hLow: bs.stop -= (bs.size div 2) else: bs.start += (bs.size div 2) proc parseBinSet(spec: string; lowChar, hiChar: char): int = var bset = newBinSet(2 ^ spec.len) for c in spec: if c == lowChar: bset.split(hLow) elif c == hiChar: bset.split(hHigh) else: raise newException(ValueError, "Bad BinSet specifier: " & spec) assert(bset.start == bset.stop) # this should never be false, but just in case result = bset.start proc loadSeats(): seq[Seat] = for line in loadStrings(5): let row = parseBinSet(line[0..6], 'F', 'B') let col = parseBinSet(line[7..^1], 'L', 'R') result.add(Seat(row: row, col: col)) result.sort(seatCmp) proc partOne(seats: seq[Seat]): int = for s in seats: if s.seatId() > result: result = s.seatId() proc partTwo(seats: seq[Seat]): int = for i, s in seats: let curId = s.seatId() let nextId = seats[i + 1].seatId() if nextId - curId != 1: # i.e. if there's a gap return curId + 1 when isMainModule: let seats = loadSeats() echo "One: ", partOne(seats) echo "Two: ", partTwo(seats)