Skip to content

Commit

Permalink
Complete AoC 2023 (#482)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akuli authored Dec 26, 2023
1 parent 1b6cbd6 commit 284c402
Show file tree
Hide file tree
Showing 8 changed files with 1,089 additions and 3 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ def main() -> int:
See the [examples](./examples/) and [tests](./tests/) directories for more example programs
or read [the Jou tutorial](./doc/tutorial.md).

So far, Jou is usable enough to do [Advent of Code 2023](https://adventofcode.com/).
We'll see whether I get 50 stars with Jou this year.
So far, Jou is usable for writing small programs that don't have a lot of dependencies.
For example, I solved all problems of [Advent of Code 2023](https://adventofcode.com/2023/) in Jou.
See [examples/aoc2023](./examples/aoc2023/) for the code.

Goals:
Expand Down
226 changes: 226 additions & 0 deletions examples/aoc2023/day24/bigint.jou
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import "stdlib/mem.jou"


class BigInt:
data: byte[48] # little endian, last byte includes sign bit


def bigint(value: long) -> BigInt:
# assumes little-endian CPU
result = BigInt{}
assert sizeof(value) < sizeof(result.data)

if value < 0:
memset(&result.data, 0xff, sizeof(result.data))
memcpy(&result.data, &value, sizeof(value))
return result


def bigint_to_long(x: BigInt) -> long:
# assume that value fits into 64-bit long
# also assume little-endian
result: long
memcpy(&result, &x.data, sizeof(result))
return result


# TODO: methods are kinda annoying because you'd need temporary values.
# e.g. foo.bar().baz() doesn't work, tries to do take address of bar() return value


# x+y
def bigadd(x: BigInt, y: BigInt) -> BigInt:
result = bigint(0)
carry_bit = 0

for i = 0; i < sizeof(x.data); i++:
result_byte = (x.data[i] as int) + (y.data[i] as int) + carry_bit
if result_byte >= 256:
carry_bit = 1
else:
carry_bit = 0
result.data[i] = result_byte as byte

return result


def bigadd3(x: BigInt, y: BigInt, z: BigInt) -> BigInt:
return bigadd(bigadd(x, y), z)
def bigadd4(x: BigInt, y: BigInt, z: BigInt, zz: BigInt) -> BigInt:
return bigadd(bigadd(bigadd(x, y), z), zz)
def bigadd5(x: BigInt, y: BigInt, z: BigInt, zz: BigInt, zzz: BigInt) -> BigInt:
return bigadd(bigadd(bigadd(bigadd(x, y), z), zz), zzz)
def bigadd6(x: BigInt, y: BigInt, z: BigInt, zz: BigInt, zzz: BigInt, zzzz: BigInt) -> BigInt:
return bigadd(bigadd(bigadd(bigadd(bigadd(x, y), z), zz), zzz), zzzz)


# -x
def bigneg(x: BigInt) -> BigInt:
# Flipping all bits (~x) is almost same as negating the value.
# For example, -7 is f9ffffff... and ~7 is f8ffffff...
for i = 0; i < sizeof(x.data); i++:
x.data[i] = (0xff as byte) - x.data[i]
return bigadd(x, bigint(1))


# x-y
def bigsub(x: BigInt, y: BigInt) -> BigInt:
return bigadd(x, bigneg(y))


# Return values:
# x < y --> -1
# x == y --> 0
# x > y --> 1
def bigcmp(x: BigInt, y: BigInt) -> int:
x_sign_bit = x.data[sizeof(x.data) - 1] / 128
y_sign_bit = y.data[sizeof(y.data) - 1] / 128

if x_sign_bit != y_sign_bit:
return y_sign_bit - x_sign_bit

for i = sizeof(x.data) - 1; i >= 0; i--:
if (x.data[i] as int) < (y.data[i] as int):
return -1
if (x.data[i] as int) > (y.data[i] as int):
return 1

return 0


# x == y
def bigeq(x: BigInt, y: BigInt) -> bool:
return bigcmp(x, y) == 0


# Return values:
# positive --> 1
# zero --> 0
# negative --> -1
def bigsign(x: BigInt) -> int:
return bigcmp(x, bigint(0))


# |x|
def bigabs(x: BigInt) -> BigInt:
if bigsign(x) < 0:
return bigneg(x)
else:
return x


# x*y
def bigmul(x: BigInt, y: BigInt) -> BigInt:
result_sign = bigsign(x) * bigsign(y)
x = bigabs(x)
y = bigabs(y)

result = bigint(0)
for i = 0; i < sizeof(x.data); i++:
for k = 0; i+k < sizeof(result.data); k++:
temp = (x.data[i] as int)*(y.data[k] as int)

gonna_add = bigint(0)
gonna_add.data[i+k] = temp as byte
if i+k+1 < sizeof(gonna_add.data):
gonna_add.data[i+k+1] = (temp / 256) as byte
result = bigadd(result, gonna_add)

if bigsign(result) == result_sign:
return result
else:
return bigneg(result)


# x / 256^n for x >= 0
def shift_smaller(x: BigInt, n: int) -> BigInt:
assert bigsign(x) >= 0
assert n >= 0

if n >= sizeof(x.data):
return bigint(0)

memmove(&x.data, &x.data[n], sizeof(x.data) - n)
memset(&x.data[sizeof(x.data) - n], 0, n)
return x


# x * 256^n for x >= 0
def shift_bigger(x: BigInt, n: int) -> BigInt:
assert bigsign(x) >= 0
assert n >= 0

if n >= sizeof(x.data):
return bigint(0)

memmove(&x.data[n], &x.data[0], sizeof(x.data) - n)
memset(&x.data, 0, n)
return x


# [x/y, x%y]
def bigdivmod(x: BigInt, y: BigInt) -> BigInt[2]:
assert not bigeq(y, bigint(0))

quotient = bigint(0)
remainder = bigabs(x)
yabs = bigabs(y)

n = 0
while bigcmp(shift_smaller(remainder, n), yabs) >= 0:
n++

assert n < sizeof(quotient.data)
while n --> 0:
# Find nth base-256 digit of result with trial and error.
d = 0
bigger_y = shift_bigger(yabs, n)
while bigcmp(bigmul(bigger_y, bigint(d+1)), remainder) <= 0:
if d == 0:
d++
else:
d *= 2
d /= 2
while bigcmp(bigmul(bigger_y, bigint(d+1)), remainder) <= 0:
d++

assert d < 256
quotient.data[n] = d as byte
remainder = bigsub(remainder, bigmul(bigint(d), bigger_y))

if bigsign(x)*bigsign(y) < 0:
quotient = bigneg(quotient)
if bigsign(x) < 0:
remainder = bigneg(remainder)

# When nonzero remainder, force its sign to be same sign as y, similar to jou %
if bigsign(remainder) != 0 and bigsign(remainder) != bigsign(y):
remainder = bigadd(remainder, y)
quotient = bigsub(quotient, bigint(1))

return [quotient, remainder]

# Tests:
#
# for x = -100; x <= 100; x++:
# for y = -100; y <= 100; y++:
# if y != 0:
# result = bigdivmod(bigint(x), bigint(y))
# assert x == (x/y)*y + (x%y)
# assert x == bigint_to_long(result[0])*y + bigint_to_long(result[1])
# assert bigint_to_long(result[0]) == x / y
# assert bigint_to_long(result[1]) == x % y


# x / y
def bigdiv(x: BigInt, y: BigInt) -> BigInt:
pair = bigdivmod(x, y)
return pair[0]


# assert x % y == 0
# x / y
def bigdiv_exact(x: BigInt, y: BigInt) -> BigInt:
pair = bigdivmod(x, y)
assert bigeq(pair[1], bigint(0))
return pair[0]
Loading

0 comments on commit 284c402

Please sign in to comment.