First solution in assembly. Linux only, sorry Windows users. It’s not perfect, and I cheat a little bit by not formatting the output, but it works well enough.
To compile and run, use the following:
gcc day01.s -no-pie -o day01 && ./day01 | od -t u1
Note: Make sure you have the letters input named “input.txt” in the current directory.
.text
.global main
main:
# open file
movl $5, %eax
movl $path, %ebx
movl $0, %ecx
int $0x80
# read entire file
movl %eax, %ebx
movl $3, %eax
movl $buff, %ecx
movl $16384, %edx
int $0x80
movl %eax, len
movl $0, pos
main_loop:
call atoi
# check if less than 0, meaning end of file
cmp $0, %eax
jl end_loop
# increment the value at the country code position in the array
movl country_counts(, %eax, 1), %ebx
inc %ebx
movl %ebx, country_counts(, %eax, 1)
jmp main_loop
end_loop:
# write
movl $4, %eax
movl $1, %ebx
leal country_counts(, %ebx, 1), %ecx
movl $196, %edx
int $0x80
exit:
# exit
movl $1, %eax
movl $0, %ebx
int $0x80
# not really a good general purpose atoi, but it works here
.global atoi
atoi:
movl $0, %eax # eax will be the resulting integer
atoi_loop:
# check if at end of string
movl len, %ebx
movl pos, %ecx
cmpl %ebx, %ecx
jge atoi_end_pre
# read a char from the buffer and increment the read position
movl $0, %ebx
mov buff(, %ecx, 1), %bl
inc %ecx
movl %ecx, pos
# check if at a space
cmp $0x30, %bl
jl atoi_end
# actual conversion here.
# multiply previous result by 10 and add current
sub $0x30, %bl
movl $10, %ecx
mul %ecx
addl %ebx, %eax
jmp atoi_loop
atoi_end_pre:
movl $-1, %eax
atoi_end:
ret
.lcomm buff, 16384 # buffer for reading the file
.lcomm country_counts, 200 # array for accumulating the letter counts, 1 byte per country
.lcomm len, 4 # total length of the file
.lcomm pos, 4 # current position in the file
.data
path:
.string "./input.txt"
First time using Gleam. I think there’s room for improvement in my solution, but it’s a start. I also see the similarity to elixir, but it’s cool they have compile-to-js.
I didn’t get file reading working at this time, so just copy/paste the contents of the file into the string.
import gleam/io
import gleam/string
import gleam/dict
import gleam/list
import gleam/option.{Some, None}
import gleam/result
import gleam/pair
import gleam/int
pub fn main() {
// Copy/paste the contents of the file into the string here
let letters = "..."
let increment = fn(x) {
case x {
Some(i) -> i + 1
None -> 1
}
}
string.split(letters, on: " ")
|> list.map(fn(code) { result.unwrap(int.parse(code), or: -1) })
|> list.fold(dict.new(), fn(acc, code) { dict.upsert(acc, code, increment) })
|> dict.to_list()
|> list.sort(by: fn(e1, e2) { int.compare(pair.first(e1), pair.first(e2)) })
|> list.map(fn(e) { int.to_string(pair.first(e)) <> ": " <> int.to_string(pair.second(e)) })
|> string.join(with: "\n")
|> io.print()
}
One question I had while writing it: Why do I need to import Some
and None
? Loose experimenting shows I don’t need to do that with Ok
and Error
.
Do you have any idea how many letters Santa gets each year before Christmas? Millions of people around the world send letters to Santa every year letting him know what they would like for Christmas. However, the logistics of not only reading those letters, but estimating labor, ordering materials, storing products, and loading up presents at the appropriate time in an efficient order requires a lot of planning.
Problem: In order to prepare for this Christmas season, some of the head elves would like a report on how many letters are coming from each country. The elves physically receiving the letters have been inputting the country code of the letter into a file named letters.txt. You need to read this file, and then report how many letters have been sent from each country.
Challenge: A letters_challenge.txt has also been included if you’d like some extra credit. There is a lot more data in this file, so it may need to be handled a bit differently so as not to overload your memory. (Note: github has limitations on file size. Feel free to use the python script to make a larger file).
Example:
Input:
1 2 34 53 1 53 6
Output:
1: 2
2: 1
6: 1
34: 1
53: 2