public static BoardBuilder parseStringToBoardBuilder(String puzzleString, boolean singleDigitOnly) {
    final Matcher matcher = VALIDATE_PATTERN.matcher(puzzleString);
    if (!matcher.matches()) {
      throw new IllegalArgumentException("illegal puzzle string: " + puzzleString);
    }
    final int width = Integer.parseInt(matcher.group(1));
    final int height = Integer.parseInt(matcher.group(2));
    final BoardBuilder result = new BoardBuilder(width, height);

    final Matcher cellMatcher =
        (singleDigitOnly ? CELL_PATTERN_SINGLE : CELL_PATTERN).matcher(matcher.group(3));
    for (int y = 0; y < height; ++y) {
      for (int x = 0; x < width; ++x) {
        if (!cellMatcher.find()) {
          throw new IllegalArgumentException("no data for cell " + x + ", " + y);
        }
        final String cell = cellMatcher.group();
        if (".".equals(cell)) {
          result.setNumber(x, y, 0);
        }
        else {
          result.setNumber(x, y, Integer.parseInt(cell));
        }
      }
    }
    if (cellMatcher.find()) {
      throw new IllegalArgumentException("to much data");
    }

    return result;
  }