Skip to content

Instantly share code, notes, and snippets.

@ayoubzulfiqar
Last active December 5, 2023 12:14
Show Gist options
  • Save ayoubzulfiqar/0888982472e9a0c17b417640b02dab09 to your computer and use it in GitHub Desktop.
Save ayoubzulfiqar/0888982472e9a0c17b417640b02dab09 to your computer and use it in GitHub Desktop.
Advent Of Code - Day 1 - Trebuchet (Go, Dart, TypeScript)

Day 1: Trebuchet

Code: Golang

// SumCalibration reads a file named "input.txt", calculates the calibration
// values for each line by combining the first and last digits, and returns
// the sum of all calibration values.
func SumCalibration() (int, error) {
	// Open the file for reading
	file, fileOpenError := os.Open("input.txt")
	if fileOpenError != nil {
		fmt.Printf("Error: %v", fileOpenError)
		return 0, fileOpenError
	}
	defer file.Close()

	// Create a scanner to read the file line by line
	fileScan := bufio.NewScanner(file)
	var sum int = 0

	// Iterate over each line in the file
	for fileScan.Scan() {
		// Get the current line
		var lines string = fileScan.Text()

		// Find the first and last digits in the line
		firstDigit, foundFirst := findFirstDigit(lines)
		lastDigit, foundLast := findLastDigit(lines)

		// If both first and last digits are found, calculate the calibration value
		if foundFirst && foundLast {
			calibrationValue := firstDigit*10 + lastDigit
			sum += calibrationValue
		}
	}

	// Return the sum of calibration values and nil error
	return sum, nil
}

// findFirstDigit finds the first numeric digit in the given string.
// It returns the digit and true if found, or 0 and false if not found.
func findFirstDigit(s string) (int, bool) {
	// Iterate over each character in the string
	for i := 0; i < len(s); i++ {
		var char rune = rune(s[i])

		// Check if the character is a digit
		if isDigit(char) {
			// Convert the digit to an integer
			digit, err := runeToInt(char)
			if err != nil {
				fmt.Printf("Conversion Error: %v", err)
			}
			return digit, true
		}
	}

	// Return 0 and false if no digit is found
	return 0, false
}

// findLastDigit finds the last numeric digit in the given string.
// It returns the digit and true if found, or 0 and false if not found.
func findLastDigit(s string) (int, bool) {
	// Iterate over each character in reverse order
	for i := len(s) - 1; i >= 0; i-- {
		var char rune = rune(s[i])

		// Check if the character is a digit
		if isDigit(char) {
			// Convert the digit to an integer
			digit, err := runeToInt(char)
			if err != nil {
				fmt.Printf("Conversion Error: %v", err)
			}
			return digit, true
		}
	}

	// Return 0 and false if no digit is found
	return 0, false
}

// isDigit checks if the given rune is a numeric digit.
func isDigit(char rune) bool {
	return (char >= '0') && (char <= '9')
}

// runeToInt converts a numeric rune to its corresponding integer value.
// It returns the integer value and nil error if the conversion is successful,
// or 0 and an error if the rune is not a numeric digit.
func runeToInt(r rune) (int, error) {
	if r >= '0' && r <= '9' {
		return int(r - '0'), nil
	}
	return 0, fmt.Errorf("Not a numeric rune: %c", r)
}

Code: Dart

Future<int> sumCalibration() async {
  final file = File('input.txt');
  try {
    final lines = await file.readAsLines();

    int sum = 0;
    for (final String line in lines) {
      final firstDigit = findFirstDigit(line);
      final lastDigit = findLastDigit(line);

      if (firstDigit != null && lastDigit != null) {
        final calibrationValue = firstDigit * 10 + lastDigit;
        sum += calibrationValue;
      }
    }

    return sum;
  } catch (e) {
    print('Error: $e');
    return 0;
  }
}

int? findFirstDigit(String s) {
  for (int i = 0; i < s.length; i++) {
    final char = s[i];
    if (isDigit(char)) {
      final digit = runeToInt(char);
      if (digit != null) {
        return digit;
      }
    }
  }
  return null;
}

int? findLastDigit(String s) {
  for (int i = s.length - 1; i >= 0; i--) {
    final String char = s[i];
    if (isDigit(char)) {
      final digit = runeToInt(char);
      if (digit != null) {
        return digit;
      }
    }
  }
  return null;
}

bool isDigit(String char) {
  return RegExp(r'\d').hasMatch(char);
}

int? runeToInt(String char) {
  if (RegExp(r'\d').hasMatch(char)) {
    return int.parse(char);
  }
  return null;
}

Code: TypeScript

import * as fs from 'fs';

async function sumCalibration(): Promise<number> {
  try {
    const fileContent: string = await fs.promises.readFile('test.txt', 'utf-8');
    const lines: string[] = fileContent.split('\n');

    let sum: number = 0;
    for (const line of lines) {
      const firstDigit: number | null = findFirstDigit(line);
      const lastDigit: number | null = findLastDigit(line);

      if (firstDigit !== null && lastDigit !== null) {
        const calibrationValue: number = firstDigit * 10 + lastDigit;
        sum += calibrationValue;
      }
    }

    return sum;
  } catch (e) {
    console.error('Error:', e);
    return 0;
  }
}

function findFirstDigit(s: string): number | null {
  for (let i = 0; i < s.length; i++) {
    const char: string = s[i];
    if (isDigit(char)) {
      const digit: number | null = runeToInt(char);
      if (digit !== null) {
        return digit;
      }
    }
  }
  return null;
}

function findLastDigit(s: string): number | null {
  for (let i = s.length - 1; i >= 0; i--) {
    const char: string = s[i];
    if (isDigit(char)) {
      const digit: number | null = runeToInt(char);
      if (digit !== null) {
        return digit;
      }
    }
  }
  return null;
}

function isDigit(char: string): boolean {
  return /\d/.test(char);
}

function runeToInt(char: string): number | null {
  if (/\d/.test(char)) {
    return parseInt(char, 10);
  }
  return null;
}

async function main() {
  try {
    const sum: number = await sumCalibration();
    console.log('Sum of Calibration Values:', sum);
  } catch (e) {
    console.error('Error:', e);
  }
}

main();

Space and Time Complexity

  1. SumCalibration:

    • Time Complexity: Let (n) be the total number of characters in the file. The function iterates through each line, and for each line, it calls findFirstDigit and findLastDigit. Both of these functions iterate through the characters of the line. Therefore, the overall time complexity is (O(n)).
    • Space Complexity: The primary space usage comes from the file reading and the variables used in the function, which are not dependent on the size of the input. Thus, the space complexity is (O(1)).
  2. findFirstDigit:

    • Time Complexity: Let (m) be the length of the input string. The function iterates through each character, and the loop has a linear time complexity of (O(m)).
    • Space Complexity: The function uses a constant amount of space for variables like char, digit, and err, so the space complexity is (O(1)).
  3. findLastDigit:

    • Time Complexity: Similar to findFirstDigit, the time complexity is (O(m)) where (m) is the length of the input string.
    • Space Complexity: The space complexity is (O(1)) since the function uses a constant amount of space.
  4. isDigit:

    • Time Complexity: The function performs a constant number of comparisons, resulting in (O(1)) time complexity.
    • Space Complexity: The function uses a constant amount of space, so the space complexity is (O(1)).
  5. runeToInt:

    • Time Complexity: The function performs a constant number of operations, resulting in (O(1)) time complexity.
    • Space Complexity: The function uses a constant amount of space, so the space complexity is (O(1)).

The space complexity of these functions is relatively low because they don't use data structures that grow with the input size. The time complexity is generally linear in the size of the input string or file.

Part - 2

Code - Golang

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

// wordToDigit is a map that converts words to their corresponding digit values.
var wordToDigit = map[string]int{
	"zero":  0,
	"one":   1,
	"two":   2,
	"three": 3,
	"four":  4,
	"five":  5,
	"six":   6,
	"seven": 7,
	"eight": 8,
	"nine":  9,
}

// SumCalibrationValues reads a file, processes each line, and calculates the sum of digit values.
func SumCalibrationValues() int {
	// Open the file named "input.txt" for reading.
	file, err := os.Open("input.txt")
	if err != nil {
		// If there is an error opening the file, return 0.
		return 0
	}
	defer file.Close()

	// Create a scanner to read the file line by line.
	scanner := bufio.NewScanner(file)
	total := 0

	// Iterate over each line in the file.
	for scanner.Scan() {
		// Get the current line.
		line := scanner.Text()

		// Variables to store the first and last digit values in the line.
		var firstDigit, lastDigit int
		var firstSet bool

		// Iterate over each character in the line.
		for i := 0; i < len(line); i++ {
			// If the character is a digit, update firstDigit and lastDigit.
			if line[i] >= '0' && line[i] <= '9' {
				dig := int(line[i] - '0')
				if !firstSet {
					firstDigit = dig
					firstSet = true
				}
				lastDigit = dig
			} else {
				// If the character is not a digit, check if it forms a word that corresponds to a digit.
				for word, digit := range wordToDigit {
					if checkWord(line, i, word) {
						if !firstSet {
							firstDigit = digit
							firstSet = true
						}
						lastDigit = digit
						break
					}
				}
			}
		}

		// Calculate the total sum based on the first and last digits of the line.
		total += (firstDigit * 10) + lastDigit
	}

	// Print the total sum.
	fmt.Printf("%v", total)

	// Return the total sum.
	return total
}

// checkWord checks if a word starting from a specific index in a line matches a given word.
func checkWord(line string, i int, word string) bool {
	return strings.HasPrefix(line[i:], word)
}

Code - Dart

import 'dart:io';

Map<String, int> wordToDigit = {
  "zero": 0,
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5,
  "six": 6,
  "seven": 7,
  "eight": 8,
  "nine": 9,
};

int sumCalibrationValues() {
  try {
    // Open the file named "input.txt" for reading.
    var file = File('input.txt');
    var lines = file.readAsLinesSync();

    // Variables to store the total sum of digit values.
    var total = 0;

    // Iterate over each line in the file.
    for (var line in lines) {
      // Variables to store the first and last digit values in the line.
      var firstDigit = 0;
      var lastDigit = 0;
      var firstSet = false;

      // Iterate over each character in the line.
      for (var i = 0; i < line.length; i++) {
        // If the character is a digit, update firstDigit and lastDigit.
        if (line[i].contains(RegExp(r'[0-9]'))) {
          var dig = int.parse(line[i]);
          if (!firstSet) {
            firstDigit = dig;
            firstSet = true;
          }
          lastDigit = dig;
        } else {
          // If the character is not a digit, check if it forms a word that corresponds to a digit.
          for (var entry in wordToDigit.entries) {
            var word = entry.key;
            var digit = entry.value;
            if (checkWord(line, i, word)) {
              if (!firstSet) {
                firstDigit = digit;
                firstSet = true;
              }
              lastDigit = digit;
              break;
            }
          }
        }
      }

      // Calculate the total sum based on the first and last digits of the line.
      total += (firstDigit * 10) + lastDigit;
    }

    // Print the total sum.
    print('$total');

    // Return the total sum.
    return total;
  } catch (e) {
    // If there is an error reading the file, return 0.
    return 0;
  }
}

// checkWord checks if a word starting from a specific index in a line matches a given word.
bool checkWord(String line, int i, String word) {
  return line.startsWith(word, i);
}

Code - TypeScript

import * as fs from 'fs';

const wordToDigit: { [key: string]: number } = {
  "zero": 0,
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5,
  "six": 6,
  "seven": 7,
  "eight": 8,
  "nine": 9,
};

function sumCalibrationValues(): number {
  try {
    // Open the file named "input.txt" for reading.
    const fileContent = fs.readFileSync('input.txt', 'utf8');
    const lines = fileContent.split('\n');

    // Variables to store the total sum of digit values.
    let total = 0;

    // Iterate over each line in the file.
    for (const line of lines) {
      // Variables to store the first and last digit values in the line.
      let firstDigit = 0;
      let lastDigit = 0;
      let firstSet = false;

      // Iterate over each character in the line.
      for (let i = 0; i < line.length; i++) {
        // If the character is a digit, update firstDigit and lastDigit.
        if (/[0-9]/.test(line[i])) {
          const dig = parseInt(line[i], 10);
          if (!firstSet) {
            firstDigit = dig;
            firstSet = true;
          }
          lastDigit = dig;
        } else {
          // If the character is not a digit, check if it forms a word that corresponds to a digit.
          for (const [word, digit] of Object.entries(wordToDigit)) {
            if (checkWord(line, i, word)) {
              if (!firstSet) {
                firstDigit = digit;
                firstSet = true;
              }
              lastDigit = digit;
              break;
            }
          }
        }
      }

      // Calculate the total sum based on the first and last digits of the line.
      total += (firstDigit * 10) + lastDigit;
    }

    // Print the total sum.
    console.log(`${total}`);

    // Return the total sum.
    return total;
  } catch (e) {
    // If there is an error reading the file, return 0.
    return 0;
  }
}

// checkWord checks if a word starting from a specific index in a line matches a given word.
function checkWord(line: string, i: number, word: string): boolean {
  return line.startsWith(word, i);
}

// Call the sumCalibrationValues function to perform the calculation.
sumCalibrationValues();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment