docs: def score_n3(matrix, matrix_size):
      """\
      Implements the penalty score feature 3.
  
      ISO/IEC 18004:2015(E) -- 7.8.3 Evaluation of data masking results - Table 11 (page 54)
  
      =========================================   ========================   ======
      Feature                                     Evaluation condition       Points
      =========================================   ========================   ======
      1 : 1 : 3 : 1 : 1 ratio                     Existence of the pattern   N3
      (dark:light:dark:light:dark) pattern in
      row/column, preceded or followed by light
      area 4 modules wide
      =========================================   ========================   ======
  
      N3 = 40
  
      :param matrix: The matrix to evaluate
      :param matrix_size: The width (or height) of the matrix.
      :return int: The penalty score (feature 3) of the matrix.
      """
      def is_match(seq, start, end):
          start = max(start, 0)
          end = min(end, matrix_size)
          for i in range(start, end):
              if seq[i] == 0x1:
                  return False
          return True
  
      def find_occurrences(seq):
          count = 0
          idx = seq.find(_N3_PATTERN)
          while idx != -1:
              offset = idx + 7
              if is_match(seq, idx - 4, idx) or is_match(seq, offset, offset + 4):
                  count += 1
              else:
                  # Found no / not enough light patterns, start at next possible
                  # match:
                  #                   v
                  # dark light dark dark dark light dark
                  #                   ^
                  offset = idx + 4
              idx = seq.find(_N3_PATTERN, offset)
          return count
  
      score = 0
      for i in range(matrix_size):
          score += find_occurrences(matrix[i])
          score += find_occurrences(bytearray([matrix[y][i] for y in range(matrix_size)]))
      return score * 40