Friday, December 1, 2023

Advent of Code 2023 - Day 1 - Salesforce Apex

Advent of Code has begun! I'll be completing this year's coding challenges using Apex. 

--- Day 1: Trebuchet?! ---

Let's dive into Day 1's challenge part 1. Setting up a reusable LWC Puzzle Input File Reader. And with Apex, I'll tackle the first part of the puzzle.

https://adventofcode.com/2023/day/1


Reusable LWC Puzzle Input File Reader

<template>
<lightning-card title="Puzzle File Reader">
<div class="slds-p-around_medium">
<lightning-input type="file" label="Select File" onchange={handlePuzzleInputChange}></lightning-input>
{puzzleInputFileName}
<div class="slds-p-top_small">
<lightning-button label="Read Puzzle Input" onclick={uploadPuzzleInput} disabled={disabled}></lightning-button>
</div>
</div>
</lightning-card>
<lightning-card title="Puzzle Result">
<div class="slds-p-around_medium">
Answer: {puzzleAnswer}
</div>
</lightning-card>
</template>
import { LightningElement } from 'lwc';
import readPuzzleInput from '@salesforce/apex/Advent.readPuzzleInput';
export default class AdventofCode_FileReader extends LightningElement {
puzzleInput;
puzzleInputFileName;
puzzleAnswer;
handlePuzzleInputChange(event) {
this.puzzleInput = event.target.files[0];
this.puzzleInputFileName = event.target.files[0].name;
}
get disabled() {
return this.puzzleInput ? false : true;
}
uploadPuzzleInput() {
if (this.puzzleInput) {
const reader = new FileReader();
reader.onload = () => {
const fileContent = reader.result;
// process the puzzle input
readPuzzleInput({ fileName: this.puzzleInput.name, fileContent })
.then(result => {
// Handle success
console.log('File uploaded successfully:', result);
this.puzzleAnswer = result;
})
.catch(error => {
// Handle error
console.error('Error uploading file:', error);
});
};
reader.readAsText(this.puzzleInput);
}
}
}
Reusable Puzzle Input Apex File Reader
public with sharing class Advent {
@AuraEnabled
public static Integer readPuzzleInput(String fileName, String fileContent) {
return read_lines(fileContent);
}
public static Integer read_lines(String puzzleInput) {
// Split by newline chars
List<String> lines = puzzleInput.split('\n');
// call puzzle solution
return day01.part1(lines);
}
}
view raw Advent.cls hosted with ❤ by GitHub
Day 01 Solution
public with sharing class day01 {
public static Map<String,String> numberMap = new Map<String,String>{
'one' => '1',
'two' => '2',
'three' => '3',
'four' => '4',
'five' => '5',
'six' => '6',
'seven' => '7',
'eight' => '8',
'nine' => '9',
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9'
};
public static Integer part1(List<String> puzzleInputLines) {
System.debug(puzzleInputLines);
Integer total = 0;
for(String line : puzzleInputLines) {
System.debug(line);
String first = firstMatch(line);
String last = lastMatch(line);
String fullMatch = first + last;
total += Integer.valueOf(fullMatch);
}
return total;
}
public static String firstMatch(String line) {
String returnVal;
// Iterate through each character in the line (first match)
for (Integer i = 0; i < line.length(); i++) {
// Get the character at the current index
String currentChar = line.substring(i, i + 1);
if(numberMap.get(currentChar) != null) {
returnVal = numberMap.get(currentChar);
break;
}
}
return returnVal;
}
public static String lastMatch(String line) {
String returnVal;
// Iterate through each character in the line in reverse order (last match)
for (Integer i = line.length() - 1; i >= 0; i--) {
// Get the character at the current index
String currentChar = line.substring(i, i + 1);
if(numberMap.get(currentChar) != null) {
returnVal = numberMap.get(currentChar);
break;
}
}
return returnVal;
}
}
view raw day01.cls hosted with ❤ by GitHub
Day 01 - Part 1 complete!
Day 01 - Part 2
Day 01 - Part 2 Solution
public with sharing class day01 {
public static Map<String,String> numberMap = new Map<String,String>{
'one' => '1',
'two' => '2',
'three' => '3',
'four' => '4',
'five' => '5',
'six' => '6',
'seven' => '7',
'eight' => '8',
'nine' => '9',
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9'
};
public static Integer part2(List<String> puzzleInputLines) {
System.debug(puzzleInputLines);
Integer total = 0;
for(String line : puzzleInputLines) {
System.debug(line);
String fullMatch = matchIncludingSpelledOutNumbers(line);
total += Integer.valueOf(fullMatch);
}
return total;
}
public static String matchIncludingSpelledOutNumbers(String line) {
List<String> returnVal = new List<String>();
// Iterate through each character in the line (first match)
for (Integer i = 0; i < line.length(); i++) {
// Get the character string at the current index to the end
String currentChars = line.substring(i, line.length());
for(String numKey : numberMap.keySet()) {
// check if starts with matches a key in the spelled out number map
if(currentChars.startsWith(numKey)) {
returnVal.add(numberMap.get(numKey));
}
}
}
return returnVal[0] + returnVal[returnVal.size() - 1];
}
}
view raw day01.cls hosted with ❤ by GitHub
Day 01 - Part 2 complete!


1 comment:

  1. Thanks for sharing, its helpful. I think we can use String.reverse() to use the firstMatch(). This way we may not need lastMatch(). Is my understanding correct ? I have not tried myself but will check on weekend.

    ReplyDelete