91 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Nim
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Nim
		
	
	
	
	
	
| 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)
 |