milkanon-he-who-assembles

Milkanon wrote a solution for day 5 in assembly, the absolute madman!
I'll let him explain how to use it:

I present to you, the solution to part 1 of day 5 of 2020 aoc, written in x86_64 AT&T GAS assembly[...]
It has 0 dependencies, and does I/O directly by invoking syscalls.

To build, do

as -o 5.o 5.s
ld -o 5 5.o
./5

you should see something like

./5
Silver star answer: 0000000820

I should note the input filename is hardcoded to "input.txt", and it must reside within the working directory from which the program ran.

[...]

The register epilogue/prologue code is just my own failure to have enough mental energy to actually adhere to a sane ABI - i simply save every single register that i use, no exclusions. makes it easier to reason about but at the cost of performance and code size.

[ I heard these new fangled "compilers" can do it automatically - as if i would ever trust some algorithm to do it for me! ]

The code is even well-commented, and thus probably the most readable code on this site, despite being in assembler.
I'm pretty sure this guy is the only Real Programmer in the AOC thread (unless there's another assembly-writer I missed).
Very cool! I'm looking forward to anything else you send in, milkanon.

milkanon/assembly-day05-1.s
milkanon/assembly-day05-1.s
    .text
    
        .global _start
        .type _start, @function
        
        .set SYS_READ, 0
        /* SYS_OPEN:
    rdi:    int fd
    rsi:    char *buffer
    rdx:    size_t count
        */
        
        .set SYS_OPEN, 2
        /* SYS_OPEN:
    rdi:    const char *filename
    rsi:    int flags
    rdx:    int mode
        */
        
        .set SYS_EXIT, 60
        /* SYS_EXIT:
    rdi:    int exitcode
        */
        
        .set O_RDONLY, 0
    _start:
        movq    %rsp, %rbp
    
        // Open input file
        movq $SYS_OPEN, %rax
        movq $filename, %rdi
        movq $O_RDONLY, %rsi
        movq $0600, %rdx
        syscall
    
        // We should have the fd in rax. Store it.
        movq %rax, fd
    
    .Lread_seat_entry:
        // Read 11 bytes.
        movq $SYS_READ, %rax
        movq fd, %rdi
        movq $buffer, %rsi
        movq $BUFFER_SIZE, %rdx
        syscall
    
        // rax returns the number of bytes read, or negative for
        // error.
        cmp    $0, %rax
        je    .Lread_all_ok
    
        // At this point, buffer looks like
        //     (gdb) p *((char [11] *)$rsi)
        //     $1 = "FFBBBFBLRL\n"
        
        // Get the row index of buffer string specifier
        call    get_row
        // Save it before it gets clobbered
        push    %rax
        // Now get the row index
        call     get_col
        // Restore rax, use (rax, rbx) as (row, col) tuple
        mov    %rax, %rbx
        pop    %rax
    
        // Mark this seat as occupied in the taken_tab
        call    mark_taken
    
        // Also calculate and store the id for this seat in id_tab
        call    store_id
    
        jmp    .Lread_seat_entry
    
    .Lread_all_ok:
        // Get the max id for Silver
        call    get_max_id
        push    %rax
        mov    $silver_str, %rax
        call    print_string
        
        pop    %rax
        call    print_number
    
        // Exit program
        movq    $SYS_EXIT, %rax
        movq    $0, %rdi
        syscall
    
        .size _start, .-_start
    
    
        .section .data
        
        /* Utility symbols */
        .set WIDTH, 8
        .set HEIGHT, 128
    
        /* File descriptor */
    fd:
        .quad 0
        
        /* Table whether or not seat is taken. */
        .align 8
    taken_tab:
        .zero 8 * (8 * WIDTH * HEIGHT)
    
        /* Table of seat ids */
        .align 8
    id_tab:    
        .zero 8 * (8 * WIDTH * HEIGHT)
    
        .set BUFFER_SIZE, 11
    buffer:
        // 7 bytes for the column string (e.g. "FFBFFBF")
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        
        // 3 bytes for the row string (e.g. "LRL")
        .byte 0
        .byte 0
        .byte 0
        
        // 1 byte for the newline
        .byte 0
    
        .section .rodata
    silver_str:
        .asciz "Silver star answer: "
    
    filename:
        .asciz "input.txt"
    
        /* Lookup table for the "BFBBBFB"-to-binary conversion */
    bintab_row:
        .quad 64
        .quad 32
        .quad 16
        .quad 8
        .quad 4
        .quad 2
        .quad 1
        
        /* Lookup table for the "LRL"-to-binary conversion */
    bintab_col:
        /* Due to the way the lookups happen, we need to offset these
        abit forward to account for how the fact that the row
        specifier appears at the end of the string. This just makes
        indexing more easier elsewhere in the code. */
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        
        .quad 4
        .quad 2
        .quad 1
        
        
        /* Helper routines */
        .section .text
        
        /* size_t get_row(void): Get row of string spec in buffer. */
        .global get_row
        .type get_row, @function
        
        /* size_t get_col(void): Get col of string spec in buffer. */
        .global get_col
        .type get_col, @function
    
        /* void mark_taken(size_t row, size_t col): Set corresponding
        seat location to '1' in taken_tab.
            rax - row
            rbx - col
        */
        .global mark_taken
        .type mark_taken, @function
    
        /* void store_id(size_t row, size_t col): Set corresponding
        seat location to the seat id in id_tab.
            rax - row
            rbx - col
        */
        .global store_id
        .type store_id, @function
    
        .global get_max_id
        .type get_max_id, @function
    
        .global print_silver
        .type print_silver, @function
    
        .global print_string
        .type print_string, @function
    
        .global strlen
        .type strlen, @function
    
    strlen:
        push    %rbx
        push    %rsi
        
        mov    %rax, %rsi
        mov    $0, %rbx
    
    .Lstrlen_loop:
        mov    (%rsi, %rbx, 1), %al
        cmp    $0, %al
        je    .Lstrlen_done
    
        inc    %rbx
        jmp    .Lstrlen_loop
        
    .Lstrlen_done:
        mov    %rbx, %rax
    
        pop    %rsi
        pop    %rbx
    
        ret
    
    print_string:
        push    %rax
        push    %rcx
        push    %rsi
        push    %rdi
    
        call    strlen
        mov    %rax, %rdx
    
        movq    $1, %rax
        movq    $1, %rdi
        movq    24(%rsp), %rsi
        syscall
    
        pop    %rdi
        pop    %rsi
        pop    %rcx
        pop    %rax
    
        ret
    
        .size print_string, .-print_string
    
    print_number:
        // I need a bit of scratch memory space cos i need
        // to give sys_write an address to a buffer
        push    %rbp
        movq    %rsp, %rbp
        
        // number to print
        push    %rax
        // index
        push    %rbx
        push    %rcx
        push    %rdx
    
        // We need to zero terminate it cos print_string
        // will be scanning for it until we get the zero
        // so $10 (MAXINT="42945967295") + $2 ("\n\0") = $12
        sub    $12, %rsp
        movb    $'\n', 10(%rsp)
        movb    $0, 11(%rsp)
        
        movq    $9, %rbx
        movq    $10, %rcx
    
    .Lprint_number_loop:
        cltd
        idiv    %ecx
        
        add    $0x30, %dl
        mov    %dl, (%rsp, %rbx, 1)
    
        cmp    $0, %rbx
        je    .Lprint_number_done
    
        dec    %rbx
        jmp    .Lprint_number_loop
    .Lprint_number_done:
    
        mov    %rsp, %rax
        call    print_string
    
        add    $12, %rsp
        
        pop    %rdx
        pop    %rcx
        pop    %rbx
        pop    %rax
    
        pop    %rbp
        ret
    
    print_silver:
        
    
        .size print_silver, .-print_silver
    
    get_max_id:
        push    %rbx
    
        push    %rdx
        push    %rsi
        push    %rdi
    
        /* Pointer to taken_tab table */
        movq    $taken_tab, %rsi
        /* Pointer to id_tab table */
        movq    $id_tab, %rdi
        /* Index */
        movq    $0, %rdx
        /* Running max */
        movq    $0, %rbx
    
    .Lget_max_id_loop:
        /* load the taken variable for this seat */
        movq    (%rsi, %rdx, 8), %rax
        
        /* if its 0, it is not taken, and therefore we skip it. */
        cmp    $0, %rax
        je    .Lget_max_id_skip
    
        /* load the id for this seat */
        movq    (%rdi, %rdx, 8), %rax
    
        cmp    %rax, %rbx
        cmovc    %rax, %rbx
        
    .Lget_max_id_skip:
        inc    %rdx
        cmp    $(128 * 8), %rdx
        jl    .Lget_max_id_loop
    
        mov    %rbx, %rax
    
        pop    %rdi
        pop    %rsi
        pop    %rdx
        
        pop    %rbx
    
        ret
    
        .size get_max_id, .-get_max_id
    
    store_id:
        push    %rax
        push    %rbx
        push    %rcx
        push    %rdi
    
        // calculate id
        imul    $8, %rax
        add    %rbx, %rax
        
        // store it in rcx
        mov    %rax, %rcx
    
        // restore rax
        mov    24(%rsp), %rax
    
        // calculate row memory location
        movq    $id_tab, %rdi
        imul    $(8 * 8), %rax
        add    %rax, %rdi
        
        // add column offset
        imul    $8, %rbx
        add    %rbx, %rdi
    
        // store id in rcx to slot in id_tab
        movq    %rcx, (%rdi)
    
        pop    %rdi
        pop    %rcx
        pop    %rbx
        pop    %rax
    
        ret
    
        .size store_id, .-store_id
    
    mark_taken:
        push    %rax
        push    %rbx
        push    %rcx
        push    %rdi
    
        // calculate id
        imul    $8, %rax
        add    %rbx, %rax
        
        // store it in rcx
        mov    %rax, %rcx
    
        // restore rax
        mov    24(%rsp), %rax
    
        // calculate row memory location
        movq    $taken_tab, %rdi
        imul    $(8 * 8), %rax
        add    %rax, %rdi
        
        // add column offset
        imul    $8, %rbx
        add    %rbx, %rdi
    
        // store presence in rcx to slot in id_tab
        movq    $1, (%rdi)
    
        pop    %rdi
        pop    %rcx
        pop    %rbx
        pop    %rax
    
        ret
    
        .size mark_taken, .-mark_taken
        
    get_row:
        push    %rbx
        push    %rcx
        push    %rdx
        push    %rsi
        push    %rdi
        push    %r8
    
        /* zero-register for cmov below */
        movq    $0, %rbx
        /* input buffer, e.g. "FFBBFFBLRL\n" */
        movq    $buffer, %rsi
        /* lookup table for (2 * %ecx) */
        movq    $bintab_row, %rdi
        /* index */
        movq    $0, %rcx
    
        /* r8 will contain the row number */
        movq    $0, %r8
        
    .Lget_row_loop:    
        /* Load in this seat ('F' or 'B' into eax) */
        mov    (%rsi, %rcx, 1), %eax
        
        /* Load in the value of this bit */
        movq    (%rdi, %rcx, 8), %rdx
        
        /* I use a trick here: Notice that 'F' = 0x46, and 'B' =
        0x42. Hence, if we subtract 'B', we get either zero or
        non-zero.  Then, we can use cmov on the zero flag to move in
        the addend. */
        cmp    $0x42, %al
        cmovnz    %rbx, %rdx
        add    %rdx, %r8
    
        inc    %rcx
        cmp    $7, %rcx
        jl    .Lget_row_loop
    
    .Lget_row_done:
        mov    %r8, %rax
    
        pop    %r8
        pop    %rdi
        pop    %rsi
        pop    %rdx
        pop    %rcx
        pop    %rbx
    
        ret
    
        .size get_row, .-get_row
    
    get_col:
        push    %rbx
        push    %rcx
        push    %rdx
        push    %rsi
        push    %rdi
        push    %r8
    
        /* zero-register for cmov below */
        movq    $0, %rbx
        /* input buffer, e.g. "FFBBFFBLRL\n" */
        movq    $buffer, %rsi
        /* lookup table for (2 * %ecx) */
        movq    $bintab_col, %rdi
        /* index (NOTE! We start at 7) */
        movq    $7, %rcx
    
        /* r8 will contain the col number */
        movq    $0, %r8
        
    .Lget_col_loop:    
        /* Load in this seat ('F' or 'B' into eax) */
        mov    (%rsi, %rcx, 1), %eax
        
        /* Load in the value of this bit */
        movq    (%rdi, %rcx, 8), %rdx
        
        /* I use a trick here: Notice that 'L' = 0x4C, and 'R' =
        0x52. Hence, if we subtract 'L', we get either zero or
        non-zero.  Then, we can use cmov on the zero flag to move in
        the addend. */
        cmp    $0x4C, %al
        cmovz    %rbx, %rdx
        add    %rdx, %r8
    
        inc    %rcx
        cmp    $10, %rcx
        jl    .Lget_col_loop
    
    .Lget_col_done:
        mov    %r8, %rax
    
        pop    %r8
        pop    %rdi
        pop    %rsi
        pop    %rdx
        pop    %rcx
        pop    %rbx
    
        ret
    
        .size get_col, .-get_col
    
milkanon/assembly-day05-2.s
milkanon/assembly-day05-2.s
    .text
    
        .global _start
        .type _start, @function
        
        .set SYS_READ, 0
        /* SYS_OPEN:
    rdi:    int fd
    rsi:    char *buffer
    rdx:    size_t count
        */
        
        .set SYS_OPEN, 2
        /* SYS_OPEN:
    rdi:    const char *filename
    rsi:    int flags
    rdx:    int mode
        */
        
        .set SYS_EXIT, 60
        /* SYS_EXIT:
    rdi:    int exitcode
        */
        
        .set O_RDONLY, 0
    _start:
        movq    %rsp, %rbp
    
        // Open input file
        movq $SYS_OPEN, %rax
        movq $filename, %rdi
        movq $O_RDONLY, %rsi
        movq $0600, %rdx
        syscall
    
        // We should have the fd in rax. Store it.
        movq %rax, fd
    
    .Lread_seat_entry:
        // Read 11 bytes.
        movq $SYS_READ, %rax
        movq fd, %rdi
        movq $buffer, %rsi
        movq $BUFFER_SIZE, %rdx
        syscall
    
        // rax returns the number of bytes read, or negative for
        // error.
        cmp    $0, %rax
        je    .Lread_all_ok
    
        // At this point, buffer looks like
        //     (gdb) p *((char [11] *)$rsi)
        //     $1 = "FFBBBFBLRL\n"
        
        // Get the row index of buffer string specifier
        call    get_row
        // Save it before it gets clobbered
        push    %rax
        // Now get the row index
        call     get_col
        // Restore rax, use (rax, rbx) as (row, col) tuple
        mov    %rax, %rbx
        pop    %rax
    
        // Mark this seat as occupied in the taken_tab
        call    mark_taken
    
        // Also calculate and store the id for this seat in id_tab
        call    store_id
    
        jmp    .Lread_seat_entry
    
    .Lread_all_ok:
        // Get the max id for Silver
        call    get_max_id
        push    %rax
        mov    $silver_str, %rax
        call    print_string
        
        pop    %rax
        call    print_number
    
        // Get our seat id for Gold
        call    find_empty_seat_id
        push    %rax
        mov    $gold_str, %rax
        call    print_string
    
        pop    %rax
        call    print_number
    
        // Exit program
        movq    $SYS_EXIT, %rax
        movq    $0, %rdi
        syscall
    
        .size _start, .-_start
    
    
        .section .data
        
        /* Utility symbols */
        .set WIDTH, 8
        .set HEIGHT, 128
    
        /* File descriptor */
    fd:
        .quad 0
        
        /* Table whether or not seat is taken. */
        .align 8
    taken_tab:
        .zero 8 * (8 * WIDTH * HEIGHT)
    
        /* Table of seat ids */
        .align 8
    id_tab:    
        .zero 8 * (8 * WIDTH * HEIGHT)
    
        .set BUFFER_SIZE, 11
    buffer:
        // 7 bytes for the column string (e.g. "FFBFFBF")
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        .byte 0
        
        // 3 bytes for the row string (e.g. "LRL")
        .byte 0
        .byte 0
        .byte 0
        
        // 1 byte for the newline
        .byte 0
    
        .section .rodata
    silver_str:
        .asciz "Silver star answer: "
    
    gold_str:
        .asciz "Gold star answer: "
    
    filename:
        .asciz "input.txt"
    
        /* Lookup table for the "BFBBBFB"-to-binary conversion */
    bintab_row:
        .quad 64
        .quad 32
        .quad 16
        .quad 8
        .quad 4
        .quad 2
        .quad 1
        
        /* Lookup table for the "LRL"-to-binary conversion */
    bintab_col:
        /* Due to the way the lookups happen, we need to offset these
        abit forward to account for how the fact that the row
        specifier appears at the end of the string. This just makes
        indexing more easier elsewhere in the code. */
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        .quad 0
        
        .quad 4
        .quad 2
        .quad 1
        
        
        /* Helper routines */
        .section .text
        
        /* size_t get_row(void): Get row of string spec in buffer. */
        .global get_row
        .type get_row, @function
        
        /* size_t get_col(void): Get col of string spec in buffer. */
        .global get_col
        .type get_col, @function
    
        /* void mark_taken(size_t row, size_t col): Set corresponding
        seat location to '1' in taken_tab.
            rax - row
            rbx - col
        */
        .global mark_taken
        .type mark_taken, @function
    
        /* void store_id(size_t row, size_t col): Set corresponding
        seat location to the seat id in id_tab.
            rax - row
            rbx - col
        */
        .global store_id
        .type store_id, @function
    
        .global get_max_id
        .type get_max_id, @function
    
        .global print_silver
        .type print_silver, @function
    
        .global print_string
        .type print_string, @function
    
        .global strlen
        .type strlen, @function
    
        .global find_emtpy_seat_id
        .type find_empty_seat_id, @function
    
    find_empty_seat_id:
        // Ok, so we have x and y to walk the entire plane.
        // We know the seat infront must not be empty,
        // and the seat behind must not be empty.
        // So we iterate over [1, 126] of the [0, 127] rows
        // (because it obviously cant be the front most or back most row)
    
        // Once we find an empty seat, look at the seat infront, and the
        // seat behind. if theyre both populated, return id in rax.
    
        // linear index of current seat
        push    %rsi
        // linear index of alternative seat
        push    %rdi
    
        // taken_tab or id_tab pointer
        push    %rdx
        // taken_tab or id_tab slot
        // We don't save it because we clobber it on return anyway.
    //    push    %rax
    
        // Load taken_tab into %rsi
        movq    $taken_tab, %rdx
    
        // Remember, it can't be the first or last row
        // so start on second row
        movq    $8, %rsi
    
    .Lfind_empty_seat_id.loop:
        // Load our seat
        movq    (%rdx, %rsi, 8), %rax
    
        // If its empty, go check the front seat.
        cmp    $0, %rax
        je    .Lfind_empty_seat_id.check_front
    
        inc    %rsi
        jmp    .Lfind_empty_seat_id.loop
    
    .Lfind_empty_seat_id.check_front:
        // Now check if the seat infront is taken
        
        // Calculate the index of seat infront
        movq    %rsi, %rdi
        subq    $8, %rdi
        
        // Lookup in taken_tab
        movq    (%rdx, %rdi, 8), %rax
    
        // If its taken, go check the back seat.
        cmp    $0, %rax
        jne    .Lfind_empty_seat_id.check_back
    
        inc    %rsi
        jmp    .Lfind_empty_seat_id.loop
    
    .Lfind_empty_seat_id.check_back:
        // Now check if the seat behind is also taken
        
        // Calculate the index of seat behind
        movq    %rsi, %rdi
        addq    $8, %rdi
        
        // Lookup in taken_tab
        movq    (%rdx, %rdi, 8), %rax
    
        // If its taken, that means we've found our seat
        cmp    $0, %rax
        jne    .Lfind_empty_seat_id.found
    
        inc    %rdi
        jmp    .Lfind_empty_seat_id.loop
    
    .Lfind_empty_seat_id.found:
        // Ok, we found an empty seat with both the front and
        // back seats taken. %rsi already has the id, return it.
        
        movq    %rsi, %rax
        
        pop    %rdx
        pop    %rdi
        pop    %rsi
    
        ret
        
        .size find_empty_seat_id, .-find_empty_seat_id
    
    strlen:
        push    %rbx
        push    %rsi
        
        mov    %rax, %rsi
        mov    $0, %rbx
    
    .Lstrlen_loop:
        mov    (%rsi, %rbx, 1), %al
        cmp    $0, %al
        je    .Lstrlen_done
    
        inc    %rbx
        jmp    .Lstrlen_loop
        
    .Lstrlen_done:
        mov    %rbx, %rax
    
        pop    %rsi
        pop    %rbx
    
        ret
    
    print_string:
        push    %rax
        push    %rcx
        push    %rsi
        push    %rdi
    
        call    strlen
        mov    %rax, %rdx
    
        movq    $1, %rax
        movq    $1, %rdi
        movq    24(%rsp), %rsi
        syscall
    
        pop    %rdi
        pop    %rsi
        pop    %rcx
        pop    %rax
    
        ret
    
        .size print_string, .-print_string
    
    print_number:
        // I need a bit of scratch memory space cos i need
        // to give sys_write an address to a buffer
        push    %rbp
        movq    %rsp, %rbp
        
        // number to print
        push    %rax
        // index
        push    %rbx
        push    %rcx
        push    %rdx
    
        // We need to zero terminate it cos print_string
        // will be scanning for it until we get the zero
        // so $10 (MAXINT="42945967295") + $2 ("\n\0") = $12
        sub    $12, %rsp
        movb    $'\n', 10(%rsp)
        movb    $0, 11(%rsp)
        
        movq    $9, %rbx
        movq    $10, %rcx
    
    .Lprint_number_loop:
        cltd
        idiv    %ecx
        
        add    $0x30, %dl
        mov    %dl, (%rsp, %rbx, 1)
    
        cmp    $0, %rbx
        je    .Lprint_number_done
    
        dec    %rbx
        jmp    .Lprint_number_loop
    .Lprint_number_done:
    
        mov    %rsp, %rax
        call    print_string
    
        add    $12, %rsp
        
        pop    %rdx
        pop    %rcx
        pop    %rbx
        pop    %rax
    
        pop    %rbp
        ret
    
    print_silver:
        
    
        .size print_silver, .-print_silver
    
    get_max_id:
        push    %rbx
    
        push    %rdx
        push    %rsi
        push    %rdi
    
        /* Pointer to taken_tab table */
        movq    $taken_tab, %rsi
        /* Pointer to id_tab table */
        movq    $id_tab, %rdi
        /* Index */
        movq    $0, %rdx
        /* Running max */
        movq    $0, %rbx
    
    .Lget_max_id_loop:
        /* load the taken variable for this seat */
        movq    (%rsi, %rdx, 8), %rax
        
        /* if its 0, it is not taken, and therefore we skip it. */
        cmp    $0, %rax
        je    .Lget_max_id_skip
    
        /* load the id for this seat */
        movq    (%rdi, %rdx, 8), %rax
    
        cmp    %rax, %rbx
        cmovc    %rax, %rbx
        
    .Lget_max_id_skip:
        inc    %rdx
        cmp    $(128 * 8), %rdx
        jl    .Lget_max_id_loop
    
        mov    %rbx, %rax
    
        pop    %rdi
        pop    %rsi
        pop    %rdx
        
        pop    %rbx
    
        ret
    
        .size get_max_id, .-get_max_id
    
    store_id:
        push    %rax
        push    %rbx
        push    %rcx
        push    %rdi
    
        // calculate id
        imul    $8, %rax
        add    %rbx, %rax
        
        // store it in rcx
        mov    %rax, %rcx
    
        // restore rax
        mov    24(%rsp), %rax
    
        // calculate row memory location
        movq    $id_tab, %rdi
        imul    $(8 * 8), %rax
        add    %rax, %rdi
        
        // add column offset
        imul    $8, %rbx
        add    %rbx, %rdi
    
        // store id in rcx to slot in id_tab
        movq    %rcx, (%rdi)
    
        pop    %rdi
        pop    %rcx
        pop    %rbx
        pop    %rax
    
        ret
    
        .size store_id, .-store_id
    
    mark_taken:
        push    %rax
        push    %rbx
        push    %rcx
        push    %rdi
    
        // calculate id
        imul    $8, %rax
        add    %rbx, %rax
        
        // store it in rcx
        mov    %rax, %rcx
    
        // restore rax
        mov    24(%rsp), %rax
    
        // calculate row memory location
        movq    $taken_tab, %rdi
        imul    $(8 * 8), %rax
        add    %rax, %rdi
        
        // add column offset
        imul    $8, %rbx
        add    %rbx, %rdi
    
        // store presence in rcx to slot in id_tab
        movq    $1, (%rdi)
    
        pop    %rdi
        pop    %rcx
        pop    %rbx
        pop    %rax
    
        ret
    
        .size mark_taken, .-mark_taken
        
    get_row:
        push    %rbx
        push    %rcx
        push    %rdx
        push    %rsi
        push    %rdi
        push    %r8
    
        /* zero-register for cmov below */
        movq    $0, %rbx
        /* input buffer, e.g. "FFBBFFBLRL\n" */
        movq    $buffer, %rsi
        /* lookup table for (2 * %ecx) */
        movq    $bintab_row, %rdi
        /* index */
        movq    $0, %rcx
    
        /* r8 will contain the row number */
        movq    $0, %r8
        
    .Lget_row_loop:    
        /* Load in this seat ('F' or 'B' into eax) */
        mov    (%rsi, %rcx, 1), %eax
        
        /* Load in the value of this bit */
        movq    (%rdi, %rcx, 8), %rdx
        
        /* I use a trick here: Notice that 'F' = 0x46, and 'B' =
        0x42. Hence, if we subtract 'B', we get either zero or
        non-zero.  Then, we can use cmov on the zero flag to move in
        the addend. */
        cmp    $0x42, %al
        cmovnz    %rbx, %rdx
        add    %rdx, %r8
    
        inc    %rcx
        cmp    $7, %rcx
        jl    .Lget_row_loop
    
    .Lget_row_done:
        mov    %r8, %rax
    
        pop    %r8
        pop    %rdi
        pop    %rsi
        pop    %rdx
        pop    %rcx
        pop    %rbx
    
        ret
    
        .size get_row, .-get_row
    
    get_col:
        push    %rbx
        push    %rcx
        push    %rdx
        push    %rsi
        push    %rdi
        push    %r8
    
        /* zero-register for cmov below */
        movq    $0, %rbx
        /* input buffer, e.g. "FFBBFFBLRL\n" */
        movq    $buffer, %rsi
        /* lookup table for (2 * %ecx) */
        movq    $bintab_col, %rdi
        /* index (NOTE! We start at 7) */
        movq    $7, %rcx
    
        /* r8 will contain the col number */
        movq    $0, %r8
        
    .Lget_col_loop:    
        /* Load in this seat ('F' or 'B' into eax) */
        mov    (%rsi, %rcx, 1), %eax
        
        /* Load in the value of this bit */
        movq    (%rdi, %rcx, 8), %rdx
        
        /* I use a trick here: Notice that 'L' = 0x4C, and 'R' =
        0x52. Hence, if we subtract 'L', we get either zero or
        non-zero.  Then, we can use cmov on the zero flag to move in
        the addend. */
        cmp    $0x4C, %al
        cmovz    %rbx, %rdx
        add    %rdx, %r8
    
        inc    %rcx
        cmp    $10, %rcx
        jl    .Lget_col_loop
    
    .Lget_col_done:
        mov    %r8, %rax
    
        pop    %r8
        pop    %rdi
        pop    %rsi
        pop    %rdx
        pop    %rcx
        pop    %rbx
    
        ret
    
        .size get_col, .-get_col
    
milkanon/input.txt
milkanon/input.txt

    FFBBBFBLRL
    BFFFBFBRRR
    BFFFBFBLRL
    BFFBFBBLRR
    BBFFBFFRLL
    BFFFBFBRLR
    FFFFBBBRLR
    BBFFFBBRRR
    BBFBFBBRRR
    BFFBBBFLRR
    FFBBFBBRLR
    BBFFBFFLLL
    BFFFBFBLLR
    FBBFFBFLRR
    FBBFBBFRRL
    BFFBBBBRRR
    BFBBBBFLLL
    BFFBFBFLRR
    FBBFFBFRRR
    FFBFBFBLRL
    BFFFFBFLRR
    FBBFFFFLRR
    BFFFBBBLLL
    BFBFFFBRLL
    FFBBBBBRLL
    FFBBFFBLLR
    FBFFBBFLRL
    FFBFFBBRRL
    BFBBBBFLLR
    BFFFFBFRRL
    BFFBFFFLLL
    FBFFFBFLRL
    FBBBFFFLLL
    FFBFBBFRLR
    FBBBFBFRRL
    BFBBBFBLLL
    FBFFFBFLRR
    FBFBFFBLRR
    BFFFFBFLRL
    FBFBFFFRRL
    FBBFBFBLRL
    FBBFFBFLLL
    FBFBBBBRRR
    FBBBBBFLRR
    FBBBFBBLLR
    FFFBFBFRLL
    FFFBBFFLRR
    BFBBFFBRRL
    FFBFBFBRRL
    FBFBBBBLRR
    BFFBBFFLLL
    FFFBFBBRRL
    BFBBFFFLRR
    FBFBFBFLRL
    BFBFFBFLLL
    FBBBFBFRLR
    FBBBFBFLLL
    BFBFFFBLRR
    BFFBFBFLRL
    BFBBFFFRRR
    FFFBFFFRLR
    FFFBBBBRLL
    FFBBBBBLLL
    BFBBBFBRLL
    FFFBBBFLLR
    BBFFFFFRRL
    FBFBBFFRLL
    BFFBFBFRLR
    FBFBBFFRRL
    FBFBBFFLLL
    FBFBBBBRLL
    FBBFFBFLRL
    BFFBFBBRRL
    FBBFBFBRRL
    FFFBBFBLRR
    BFFBBBFRLL
    FBFFFFFRRR
    BFFFFBBLRR
    FBBFFFBRRL
    FBBBBBBRRR
    FFFBBFFLLR
    BBFBFFFRRL
    BBFFFFBRRL
    FBBBFBFLRL
    FFBFBBFRRR
    FFBBBFFLRL
    BFFBFFFLRL
    BFBFBFBRRR
    BFBBFFBRLL
    BFFFFBBLLR
    FBBBFBBLRR
    BFFBFFFLRR
    BFFFBFBLLL
    FBBBBBFRRR
    BFFBFBFLLL
    FBFFBFFRRL
    BFBBFBBRRR
    FBFFFBFRRL
    BFBBBFBLLR
    BFBBBBBRRR
    FFFBFBFRRL
    BFFFBFFLLL
    BFFFFFFLRR
    FFBBFFFRLL
    BFFBFFFRRR
    BBFFBBFLRL
    FBFBBBBLLR
    FFFBFFBLRL
    FFBBBBBRLR
    FBFFBFFRRR
    BFBBFBBRLR
    FBFBBBBLRL
    BFBBFFFLLR
    FBBBFBBLRL
    BFFBBBFLLR
    FFFBBBBRRR
    BBFBFFFLRL
    FBFBBFFLLR
    BBFFFFBLRR
    FFBBFFBRRR
    FFBBBFBRLL
    BFFFFBFLLL
    BBFFBFBRLR
    FBFBBFBRRL
    FFFBBBFRRR
    FBBBFBBRRL
    FFFBFBBRRR
    FBFFBBBRLL
    FFBFBBBRLR
    BFFFBBBRLL
    FBBFBBBRLL
    FBBBBBBLLR
    FBFBBFBLRR
    BFBFBFBLRL
    FFFBFFBRLR
    BFFFFFFRLL
    BFFBFBBLRL
    FBFFBFFLRR
    FBFBBBBRLR
    BBFFFBBLRL
    FBBBFBBRRR
    BBFBFBFRRR
    FBFBFFFLRR
    BBFBFFBLLL
    FBBBFFFLLR
    BFBFFBFRRL
    BFBBBBFRLL
    FFBFBFFLRL
    FBBBBFBLRR
    FBBBBFFLLR
    FFBBFFBLLL
    FBFFFBBRRR
    FFBBBBFLLR
    BFBFBFFRRL
    FFBBBBBLRR
    BFFFFFFRRL
    BBFBFFFLRR
    BFFBFBFRRL
    BBFFBBBRRR
    BBFFBFFLRL
    FFFBFFBRRR
    BFBFBBFRLR
    BBFBFBBLRR
    BFBBBBBRLL
    FBBBFFBRRL
    FBBBBBBRLL
    FBBFBBFRLR
    FBBFFFFRRL
    BFBFFBFRRR
    BFBBFFFLLL
    FBFFBFFLLR
    BFBBBFBLRR
    BFFBBBBRLL
    FBBBBBBLRR
    FFBFFBFRRL
    BBFFFBBRLL
    FBFFFBBRLL
    FFBBFFFLRL
    BFBBBBFRRL
    FFBFFBBRRR
    BFFBBFBRLL
    FFBFFFBLLR
    FFBFFFFLLL
    FBBBBBFLLR
    FBFBFBBLLR
    FBFBBFBRRR
    BFBFFFFLRR
    BFBBFFBRRR
    FBFBFFFRRR
    FFBFBBBRLL
    BFBBBFBRRL
    BFFBBBFLRL
    BBFBFFFRLR
    BBFBBFFLRR
    FBBFFBBRRL
    FBFBBBFLRL
    FFBFBBFRRL
    BFBFFBFLRL
    BFFFBFFRLR
    BBFBBFFRLR
    FFBFBFBLLL
    BFBFFBBRRR
    BBFFBBBRRL
    FBBBFBBLLL
    FFFBFFFLRL
    BBFFBFBLLL
    BFBBFFFRLR
    FBBBBFBLRL
    BFBFBBBLRL
    FFFBFBFRLR
    FBFFFFBRRL
    BFFBBFFLLR
    FBFFFFFRRL
    FBBFFBFRLR
    FBBBFBBRLL
    FBFFFFFLLR
    BFBFBBBLLR
    FFBBBBBRRR
    BFFFBBFLLR
    FBFBBFBLLL
    FBBFFFFLLR
    FBFFFFBLRL
    FBBBFBBRLR
    FBBFBBFLRR
    FBBBBBBRRL
    BBFBFBFLRL
    FFBBBBFRRL
    BFBBFBFLRL
    BFFFFFFRRR
    BBFBFBBLRL
    BFBFFFFRLL
    BBFFBFBRRR
    BFBFFBBLLR
    FBFBFFBRRL
    FFBBFBFLLL
    BFBFBBBRLR
    FFBBFBFLRL
    BBFFFFFRRR
    FBFFFFFLRL
    FFBFBFBRLL
    BBFFFFFLRR
    BBFFFBBRLR
    FBFBBFBRLR
    FBBBBBFLRL
    FBBFFFBLRR
    FFFBBFBLLL
    BBFBFFBRLL
    FFBFBFBLLR
    BFBBFBBRRL
    BFFBFFBLLL
    BBFFBFFRLR
    BBFFBBFLLR
    BFFFFFBLRL
    FBBFFFBLLL
    FBFFFFBLLR
    FBBFBFFRRL
    BFBBBFFRRL
    BBFFFBFLRL
    FBFBFBFLLR
    FBFFFBBRLR
    BBFFBFBRLL
    BBFFBFFRRL
    BBFFBBFRLR
    FBFFBFBRLL
    BFBFBBFRRR
    BFBBFBBLRL
    FFBBFFBRLL
    FBFFBFBRLR
    BBFBFBBLLR
    BFBBBFFRLL
    FFBFFBFLLL
    BFBFFBFRLR
    BFFFBBFLRL
    BFFFBBBLRL
    BFBBBFFLLR
    FBBFBBFRRR
    BFFBFFBRRL
    BFBFFBBRRL
    BFBBFBFRLL
    FBBFFBFRLL
    FFBBBBFRLL
    FBBBFFBRLL
    BBFFBFBLRL
    BBFFFFFLLL
    BBFFFFBRRR
    FBBBBFBRLR
    BFFBFFBRRR
    FFBFBFFRLL
    FFFFBBFRRR
    BBFBBFFLRL
    FFFBBBFLRR
    BFFBFBBLLL
    BFBBFFFLRL
    BFFBFFFRLL
    BFBFFBBRLL
    FFBBBBFLLL
    BFFBFBBRRR
    BFBBBBFRRR
    FFBFFFFRLR
    BFBFBFFRRR
    BFBFBBBLRR
    FBBBFFFLRR
    FFBFFFBRRL
    FBBFFFBRLR
    FFFBFFBRLL
    BFBBFFBLLR
    FFBBFBBLRL
    FFBFFFBRLR
    BFBBFFFRLL
    FBBFBBBLLL
    FBBFFFFLLL
    FFBFBBBRRR
    FFFBBBFLRL
    BBFFBBFLRR
    FFFBFFFRLL
    FFBBFBFRRR
    FBFFBFBRRR
    BFFBBFBLRL
    FFFBBBFRLL
    FBBBFFBRRR
    FFBBBBFLRL
    FFBFBBBRRL
    FBFBFFBRRR
    FBFFFBBLLL
    FBBFFFFLRL
    BFFFFBBRLR
    BFBBBBBRLR
    BBFFFBBRRL
    BBFBFBFRLR
    FBFFFFFLLL
    FBFBBBBRRL
    BFBFFFBLRL
    FFFFBBBLLR
    FFBBBFBRLR
    FBBFFFFRRR
    BBFBFFBLRL
    BBFFFFBLRL
    BFBFFBFLRR
    FFFBBBBLRR
    FBBBBBBLRL
    FBBFFBFRRL
    FBFFBBBRRL
    FBFFBBFRRL
    FFFBFBFLLR
    BBFFFFFRLL
    FFFBBBBLLR
    BBFFBBBLRR
    FBFBFFBLLR
    BFBBFBBRLL
    BFFFFFBRLR
    FFFBFBBLRR
    BFFBBBBLLL
    BFFBBFBLLR
    FBBBBBFRLR
    BBFBFFBRLR
    FBFFBFFLLL
    FBBFBBBLLR
    FFFFBBBRRL
    FBBFBBFRLL
    BFBFFFFRLR
    FFFFBBBRLL
    BFBBBFFLLL
    BFBFBFFRLR
    FBFBFFBRLL
    FBBBFFFRLL
    FBFBFFBRLR
    FBBBBFFRLR
    BBFBFFFRLL
    BFFBBBBRLR
    BFBFFFFRRL
    FBBBFFFRRR
    FFBFFBBRLR
    FFBBBBFLRR
    BBFBBFBRRL
    BFFBFFBLLR
    BBFBBFBRLL
    FBFFBFBLLR
    BBFBFBFLLR
    FBFBFBBRLR
    BBFBBFFRRL
    BFBFFFBLLR
    BFBFFBBLLL
    FBFFBFBLRR
    BFBBBBBLLL
    BFFFBFFRRL
    BFBBBFBRLR
    BBFFFBFRLL
    BFFBFFBRLL
    BBFBBFFLLL
    BFBBBBBLRR
    FFFBFFBLLL
    BBFFBBBRLL
    FFFBBBBLRL
    FFBBBFBLLR
    FFBBFFBLRL
    FFBBFFBLRR
    FBBBBBBRLR
    BFFFBBBLLR
    FBBFBFBLRR
    FBFBFBFRLR
    FFBFBBBLRR
    FFFFBBBLRL
    FFFBBFFRLL
    FFFBFFFLRR
    BBFFFFBLLR
    BFBFBFFLLL
    FFBBBFFRLR
    FBBFBFBRLL
    FFBBBFBLLL
    FBBFFFBLLR
    BBFBFFBLRR
    BFFFFBBLLL
    FBBBFBFLLR
    FFBBBFFLRR
    BFFBBBFRRR
    FFBFFFBLRR
    FBBFFBBRLR
    BFBBFBFLRR
    FFFBBFFRRR
    FFBFFFFRLL
    FFFBFBFRRR
    FFBFFFFRRR
    FBBFBBBLRL
    FFFBFBBRLR
    FBBFFFBRLL
    FFBFBFFRLR
    FBBBBFFRRR
    BFBFFBBLRR
    FBFFBBBLRL
    FBBFBBFLLR
    BBFFFFFLRL
    BFBBFBFRLR
    BFFBFFBLRR
    FFBFFFBRLL
    FBFBFFBLLL
    BFFFFFBLLL
    FBFFBBFLLL
    BFBFFBBRLR
    FBFBBFBRLL
    FFBBFBBRLL
    BFFFBBBRLR
    BFFFFFFLRL
    BBFFFBBLLR
    BFBFBBFLRL
    FFBBBFFRRL
    BBFFFBFLLL
    BBFFBBBLLL
    BBFFBFBLLR
    FBFBBBFRLL
    FFBBBBBRRL
    FFBBBFFLLR
    FFBFBBBLRL
    BFFBFFBLRL
    BFFFBFFRRR
    BFBFFFBRRR
    FFFBBBFRLR
    FFBBFBBLLR
    BFFFBBFLRR
    FFBBBBFRRR
    BFBFBBFLRR
    FFFBBBBRRL
    BFBFFBFRLL
    FBFFBFFRLR
    FBBFFFFRLR
    BFBBBBBLRL
    FFBBFBBLLL
    FFBFBBFLLR
    BFFBBBBLRL
    BFBFFFFLRL
    BBFFFBFRRL
    FFBFFBBLRR
    FBFBFBFRRR
    BBFFFBFRLR
    BFBBBFFLRR
    BBFBFFBLLR
    BBFBBFBLLR
    FBFFFBFRLL
    BFBFBBBLLL
    FBBFBFFLRL
    BFFFBBBLRR
    BBFBFFBRRR
    FBBFFFFRLL
    BFFFBBBRRL
    FBBFBBBRRR
    FBBFFBFLLR
    BFFFFFBRRL
    FBFFFFBRLR
    FBFBFBBRRR
    FBFBFBFRLL
    BFFBFFFRRL
    FFFBBFFRRL
    BFBFFFBRLR
    FBBFBFFLRR
    BFFFBFBRRL
    FBFBBBFLLR
    FBFBBBFRRR
    FBFFBFBLRL
    FFFFBBBRRR
    FFBBBFFRRR
    FFFBFBFLLL
    BFBBFFBLRR
    FBBFBFBRRR
    BBFFBBFRRL
    BBFFBFFRRR
    BBFFBFFLRR
    FBBFFBBLRR
    BFBFFFFRRR
    BFFBFBBRLR
    BFFFBBFRLL
    BFBFBBBRLL
    BBFFFBBLRR
    FFBBFBFLRR
    FBFBBBFLLL
    BBFFBBBLLR
    FFBBFFFLRR
    FBFFFBFRRR
    BFBBFBBLLR
    FFBBFBFRLR
    BFBFFFFLLR
    FBBBFBFRRR
    BFBBFBFRRR
    BFFBFBFRRR
    FFBFBBBLLR
    FBFBFFFRLR
    FBBFBFBLLL
    BFFBBFFRLL
    FBBBBFBLLR
    FFFBBBFLLL
    BFBFBBFRLL
    FFFBFBFLRR
    FBBBBFBLLL
    FFBBFBFRLL
    BBFFBBFRRR
    FFBFFBFRLL
    FBFBFBBLLL
    FBFFBBBLLR
    FFFBFBBLRL
    FFFBBFBRRR
    FBFFBFFLRL
    FBBFBFBLLR
    BFBBBBFRLR
    FBBFBFBRLR
    FFFBFFBRRL
    FBFBBFBLLR
    BFFBFFFRLR
    FFBFBFBLRR
    BFBFBBBRRL
    FBFFFFFLRR
    FFFBBFFLLL
    BFFFBBFRLR
    FFBFFBFRLR
    BBFFFFBRLR
    BFFBFFBRLR
    BFBFBFBRLR
    FFBFFBBRLL
    FBBBFFBLLL
    BFBBBBBLLR
    BFFFFBFRLL
    FBBFFFBRRR
    FFFFBBBLLL
    FBFBFBBRRL
    FBFFFFFRLR
    FBFFBBFRRR
    BFFBBFFLRL
    BFBFBBBRRR
    FBBFBFFRLR
    BFFBBFBRRL
    BFBBFBFRRL
    FBFFFBBRRL
    FBBFFBBLLL
    FBFBFBBRLL
    BFFFFBFRRR
    FBBBFFBLLR
    FBBFBBBLRR
    FFBFBFFLLR
    FBFFBFFRLL
    FBBBFFBRLR
    FBFFBBBLLL
    FBFBFBFRRL
    BBFBBFBLLL
    FFBFBFFRRL
    FBBBFFFRRL
    FBFFBBFLRR
    FBFBFFFLLR
    BFFFFBBLRL
    BFBFBFFLRL
    FBFFFFBLLL
    FBBBFFFLRL
    BFFBBBBLLR
    BFFBBBFLLL
    BFFBBFBRRR
    FBBBFBFRLL
    BBFBFFFRRR
    BFBBBFFRLR
    FFBFBFBRRR
    FBFFBBFRLL
    FFFBBBBLLL
    FBFFBFBRRL
    BFFFFFBLLR
    BFBFFFBLLL
    FBFBBBBLLL
    BFFBBFFRRL
    BBFFBFBRRL
    FBBFBFFRRR
    BFBBFFBLLL
    BFBFFBBLRL
    BBFFFFFLLR
    FFBFBBFRLL
    FFBFFBFLLR
    FBBFFBBLRL
    BBFFFFBLLL
    BFFFBFFLLR
    FBFFFBFLLL
    BBFBFBFLLL
    FFBFFBBLRL
    FBFFBBBRLR
    BFFFFBBRRL
    FFBBBBBLLR
    FFBBFBFRRL
    FFBFBBFLRL
    FFBFBFFLRR
    FFFBFFBLLR
    BBFBFBBRLL
    BFBBBBBRRL
    FBFBBBFRLR
    FBFBFFFRLL
    BFFFFFFLLR
    FBBBBFFLLL
    FBBBFFBLRR
    BFFFBFBLRR
    FBBBFFFRLR
    BFFFFFBRLL
    FBBBBFBRRL
    BFBBBFBLRL
    FFBBFBBLRR
    BFFBBFBLLL
    BFBBFFFRRL
    FBBBBFFRRL
    BFFFBBFRRR
    FFFBFFFRRR
    FBFBBFBLRL
    BFBBFFBLRL
    BBFBBFBRLR
    BBFBBFBLRL
    FFBFBFFRRR
    BBFFBBFLLL
    FBBBFFBLRL
    FBBFFBBRRR
    BFFBFBFLLR
    FBFBFBBLRR
    BFFFBBBRRR
    FBBFBFFLLL
    FBFBBFFLRR
    FFBBFFBRLR
    FFBBBBBLRL
    FFBBBFBRRL
    BFBFBFBLRR
    FBFFFFFRLL
    BFBFBBFLLL
    BBFBFBBRRL
    FBFBFBFLLL
    FFBFFBBLLR
    FFFBFFFLLR
    BFFFBFBRLL
    FBBFFBBRLL
    FBBFBFFLLR
    BFFFFBFLLR
    BFFFFFBLRR
    BBFFFBFLRR
    FBFBBFFRLR
    BFBBFBFLLL
    BFFBBBFRLR
    BBFBFBBRLR
    FFBBFBFLLR
    BBFBFBFRRL
    FBFBFBBLRL
    FBFFFBBLRR
    FBFBBFFRRR
    BFFFFBFRLR
    FBFFFBFLLR
    FFBBBFFRLL
    FBFBFFFLRL
    BFFFBBFLLL
    FFFBBFBRLL
    FFBBBFFLLL
    BFBBFBFLLR
    FFBFBBFLLL
    BFFBBBBRRL
    BBFFBBBLRL
    FBFFFFBLRR
    BFBBFBBLRR
    BFBBBFBRRR
    BBFBFFFLLL
    BFFBBFFRLR
    BFFFBFFLRL
    FBBBBFFRLL
    FBFFBBFLLR
    FBFBFFFLLL
    BFFBBFFLRR
    FFBBFBBRRL
    BFBFBBFLLR
    FFFBBFBLRL
    FFBBFFFRRR
    BBFFFBFRRR
    FBBBBFFLRL
    FFFBFBBLLL
    FFFBBFFRLR
    FBFFFBBLRL
    BBFBFBFRLL
    BBFFBBBRLR
    FFFBBFBRLR
    BBFBBFFRLL
    BBFFFFFRLR
    BFBFBFBLLL
    BBFBFFFLLR
    FBFFBFBLLL
    BBFFFBBLLL
    FBFFFFBRLL
    BBFFFFBRLL
    FFBFFFBRRR
    BFFFFFFRLR
    BBFFBBFRLL
    BFBFFFBRRL
    FFBBBBFRLR
    FFBFFBFRRR
    BBFBFBFLRR
    FFBFFBFLRL
    BFBFBFFLLR
    FBBBBBFLLL
    FFBFFFBLLL
    FFBBBFBLRR
    FFFFBBFRRL
    FBFBBBFLRR
    BFFBBFFRRR
    FBFBBBFRRL
    BFFFFFBRRR
    BFBFBBFRRL
    BFBFBFBRLL
    BFBFFFFLLL
    FBBBBBFRRL
    BFBBBBFLRR
    BBFBBFFRRR
    BFFBFFFLLR
    BFBBFBBLLL
    FBFFFFBRRR
    FBFFFBFRLR
    BFFBFBBRLL
    FFBBBFBRRR
    FFBBFFFLLR
    BBFBBFFLLR
    BFBBFFBRLR
    FFFBBFFLRL
    BFFFFFFLLL
    FFBBFFFRLR
    BFFBFBFRLL
    FFBFFBBLLL
    BFFFBFFLRR
    FFBFFFFLRR
    FBBBBFBRLL
    BFBFFBFLLR
    FFBBFFBRRL
    BFFBBFBLRR
    FFBFFBFLRR
    BFFBFBBLLR
    FBBFBBFLLL
    FBFFBBBLRR
    BBFFBFFLLR
    BFBBBFFRRR
    FFFBFFFRRL
    FBBFBBBRRL
    FFFBFBBLLR
    BFFFBFFRLL
    BBFBFFBRRL
    FFBFFFFRRL
    FFBFBFBRLR
    FBBFBFFRLL
    FFFBBFBLLR
    FFFBBBFRRL
    FBBBBBFRLL
    BFFFBBFRRL
    BFBFBFBRRL
    FBBBBFFLRR
    FFFBBFBRRL
    BFFBBFBRLR
    BBFBFBBLLL
    FFBFFFFLLR
    FFBFFFFLRL
    FFFFBBBLRR
    BBFBBFBLRR
    FBBBFBFLRR
    FFFBFBBRLL
    FBFFBBFRLR
    FFBFBBFLRR
    FFFBFBFLRL
    FFFBBBBRLR
    FBBFBBBRLR
    FBFBFFBLRL
    BFBBBBFLRL
    BFFFFBBRRR
    BFFBBBFRRL
    BFFFFBBRLL
    BFBFBFFLRR
    BBFFBFBLRR
    FBBFBBFLRL
    FFFBFFFLLL
    FBBBBFBRRR
    FBFFFBBLLR
    FBBFFBBLLR
    FFBBFFFLLL
    FFBFBFFLLL
    FBFBFBFLRR
    BBFFFBFLLR
    BFFBBBBLRR
    FBBFFFBLRL
    FFFBFFBLRR
    BFBFBFBLLR
    FBFBBFFLRL
    BFBFBFFRLL
    FFBFBBBLLL
    FBFFBBBRRR
    FFBBFFFRRL
    FFBBFBBRRR
    FFBFFFBLRL
    BFBBBFFLRL
    

Tags: assembly