21 Востаннє редагувалося koala (05.12.2021 19:59:30)

Re: Advent of Code

2021_5a.rs
type Line = ((i32, i32),(i32, i32));

fn parse_vents(lines: &str) -> Vec<Line> {
    lines.lines()
         .map(|line|{
            let mut line = line.split(" -> ");
            let mut pt1 = line.next().unwrap().split(',');
            let mut pt2 = line.next().unwrap().split(',');
            ((pt1.next().unwrap().parse().unwrap(), pt1.next().unwrap().parse().unwrap()),
             (pt2.next().unwrap().parse().unwrap(), pt2.next().unwrap().parse().unwrap()))
        })
        .collect()
}

fn is_diagonal(line: &Line) -> bool {
    line.0.0 != line.1.0 && line.0.1 != line.1.1
}

fn ordering_to_i32(order: std::cmp::Ordering) -> i32{
    match order {
        std::cmp::Ordering::Greater =>  1,
        std::cmp::Ordering::Equal   =>  0,
        std::cmp::Ordering::Less    => -1,
    }
}

fn task(vents: &[Line], is_diagonals_needed: bool) -> i32
{
    use std::collections::HashMap;
    let mut known_vents : HashMap<(i32, i32), i32>= HashMap::new();
    for vent in vents {
        if is_diagonals_needed || !is_diagonal(vent) {
            let (mut x, mut y) = vent.0;
            let (dx, dy) = (-ordering_to_i32(x.cmp(&vent.1.0)),-ordering_to_i32(y.cmp(&vent.1.1)));
            loop {
                *known_vents.entry((x,y)).or_insert(0) += 1;
                if (x,y) == vent.1 {
                    break;
                }
                x += dx;
                y += dy;
            }
        }
    }
    known_vents.values().filter(|&&x|x>1).count() as i32
}

fn task1(vents: &[Line]) -> i32
{
    task(vents, false)
}


fn task2(vents: &[Line]) -> i32
{
    task(vents, true)
}

fn main() {
    let input = aoc::get_input_from_ini_with_year("5","2021").unwrap();
    let vents = parse_vents(&input);
    println!("Result1: {}", task1(&vents));
    println!("Result2: {}", task2(&vents));
}

Друге рішення - 25мс, перше - 4мс (у релізі, звісно, дебажні - 0,5с на 0,25с).
І так, на жаль, bench досі доступний лише на нестабільній гілці.

22

Re: Advent of Code

koala написав:

Модифікував

2021/5a.py

import aoc

import os
from collections import defaultdict

NUMBER = os.path.basename(__file__).removesuffix('a.py')

def is_non_diagonal(pts: list[list[int]]) -> bool:
    diff = [pts[0][0]-pts[1][0], pts[0][1]-pts[1][1]]
    return 0 in diff


def task(data: str, *, filter: bool) -> int:
    vents = defaultdict(int)
    for line in data.splitlines():
        line = [[int(x) for x in part.split(',')] for part in line.split('->')]
        if filter and not is_non_diagonal(line):
            continue
        x,y = line[0]
        dx = 1 if line[1][0]>x else -1 if line[1][0]<x else 0
        dy = 1 if line[1][1]>y else -1 if line[1][1]<y else 0
        while True:
            vents[(x,y)]+=1
            if [x,y]==line[1]:
                break
            x += dx
            y += dy
    return sum(1 for count in vents.values() if count>1)


def task1(data: str) -> int:
    return task(data, filter=True)
       
def task2(data: str) -> int:
    return task(data, filter=False)

if __name__ == '__main__':
    data = aoc.load_data(NUMBER, verbose=True)
    print('Task1:', task1(data))
    print('Task2:', task2(data))

Відсотків на 10 повільніше за попереднє (0.18c проти 0.16c)

Treba quote zaminyty na code

І так, на жаль, bench досі доступний лише на нестабільній гілці.

Ja protupyv dekiljka sekund: nabrav «Rudy…» zamistj «Ruby bench» i menji pokazuvalo lavotcky.

23

Re: Advent of Code

Дякую, виправив.

Це взагалі Rust, але то таке :)

24

Re: Advent of Code

Ctcosj ja sjoʼdnja vzahalji neuvagnyj, xex.

25 Востаннє редагувалося koala (06.12.2021 01:15:19)

Re: Advent of Code

День 5. 1. Є цілочисельні координати відрізків прямих: горизонтальних, вертикальних і діагональних під 45°. Треба знайти кількість цілочисельних точок перетину чи накладання цих відрізків, крім діагональних. 2. І діагональних теж.

26 Востаннє редагувалося koala (06.12.2021 09:48:38)

Re: Advent of Code

День 6. 1. Є популяція риб. Кожна риба народжує кожні 7 днів, крім новонароджених, які народжують на 9-й день. Є початковий стан (вік/час до народження) риб, обчислити кількість риб за 80 днів. 2. За 256 днів.

Тут щось фібоначчіподібне, але надто просто симулюється і початковий стан дещо все плутає, тому без специфічних формул.

2021/6.py
import aoc

import os

NUMBER = os.path.basename(__file__).removesuffix('.py')

def simulate(data: str, time: int) -> int:
    fishes = [0]*9
    for age in data.split(','):
        fishes[int(age)] += 1
    for _ in range(time):
        fishes = fishes[1:]+fishes[:1]
        fishes[6] += fishes[8]
    return sum(fishes)

def task1(data: str) -> int:
    return simulate(data, 80)
        
def task2(data: str) -> int:
    return simulate(data, 256)

if __name__ == '__main__':
    data = aoc.load_data(NUMBER, verbose=True)
    print('Task1:', task1(data))
    print('Task2:', task2(data))
2021_6.rs
fn simulate(mut state: [usize; 9], time: usize) -> usize
{
    for _ in 0..time {
        let giving_birth = state[0];
        for i in 0..8 {
            state[i] = state[i+1];
        }
        state[6] += giving_birth;
        state[8] = giving_birth;
    }
    state.iter().sum()
}

fn task1(state: &[usize; 9]) -> usize
{
    simulate(*state, 80)
}


fn task2(state: &[usize; 9]) -> usize
{
    simulate(*state, 256)
}

fn main() {
    let input = aoc::get_input_from_ini_with_year("6","2021").unwrap();
    let mut state = [0; 9];
    for fish in input.split(',').map(|x|x.parse::<usize>().unwrap()) {
        state[fish] += 1;
    };
    println!("Result1: {}", task1(&state));
    println!("Result2: {}", task2(&state));
}
Подякували: dot1

27 Востаннє редагувалося dot (06.12.2021 18:39:59)

Re: Advent of Code

Ex, tcerez druhu zadatcu musyv pererobjaty, v pidsumku otrymav duge korotku proqu, bo tut tupo zsuv masyva z dekotrymy vidminostjamy.

2021#6, Py3.9.5
fishes = [list(map(int, open("input.txt").readline().split(","))).count(i) for i in range(9)]

for _ in range(256):  # For Part One: 80
    fishes = fishes[1:7] + [fishes[0] + fishes[7], fishes[8], fishes[0]]

print("Answer:", sum(fishes))

Pro vsjak, ja znaju, ge mnogyna do fish je fish.

28

Re: Advent of Code

О, за що я люблю Пайтон - це за можливість дуже коротко записати купу операцій.
Ваш код взагалі 9 разів відкриває файл, читає і парсить з нього стрічку, причому два останніх - гарантовано з результатом 0 :)
Але в один рядок.

29 Востаннє редагувалося dot (06.12.2021 22:07:28)

Re: Advent of Code

Ваш код взагалі 9 разів відкриває файл, читає і парсить з нього стрічку, причому два останніх - гарантовано з результатом 0 :)

Slucno, prytomnjice bulo by vynesty, np:

data = list(map(int, open("input.txt").read().split(",")))
fishes = [data.count(i) for i in range(9)]

Ale podurkuvaty zarady odnoji stritcky — beztsjino, :D.

Подякували: koala1

30

Re: Advent of Code

fishes = list(map(data.count, range(9)))

як вже на те. Гм...

Подякували: dot1

31 Востаннє редагувалося koala (07.12.2021 21:32:35)

Re: Advent of Code

День 7. 1. Є масив чисел, треба знайти таке, сума відстаней від якого до кожного іншого буде мінімальною, і повернути цю суму відстаней. 2. Те саме, але функція відстані між числами a та b - |a-b|*(|a-b|+1)/2.

Перше завдання - це просто медіана. Я так і зробив спершу. А от друге - треба трохи з математикою пововтузитися, там має бути розв'язок через похідні і бісекцію, але мені ліньки, тому досить тупо шукаю бісекцію з додатковими перевірками сусідів (фактично за градієнтом). Для загальності перше теж переробив.

2021/7.py
import aoc

import os
#import statistics
from typing import List, Callable
from functools import cache
import unittest

NUMBER = os.path.basename(__file__).removesuffix('.py')

#def task1_old(data: str) -> int:
#    data = [int(x) for x in data.split(',')]
#    median = int(statistics.median(data))
#    return sum(abs(position - median) for position in data)

def task(data: List[int], fuel: Callable[[int, int], int]) -> int:
    @cache
    def func(pos):
        return sum(fuel(crab, pos) for crab in data)
    pos = (data[-1]-data[0])//2
    step = (data[-1]-data[0])//4
    
    while True:
        dist = func(pos)
        dist_l = func(pos-1)
        dist_r = func(pos+1)
        if dist_l>=dist<=dist_r:
            return dist
        elif dist_r<dist:
            pos += step            
        else:
            pos -= step
        step = step//2 or 1        step = step//2 or 1

def task1(data: List[int]) -> int:
    return task(data, lambda crab, pos: abs(pos-crab))

def task2(data: List[int]) -> int:
    return task(data, lambda crab, pos: abs(pos-crab)*(abs(pos-crab)+1)//2)

class Test(unittest.TestCase):
    def test_task1(self):
        data = sorted(int(x) for x in [16,1,2,0,4,2,7,1,2,14])
        self.assertEqual(task1(data),37)
    def test_task2(self):
        data = sorted(int(x) for x in [16,1,2,0,4,2,7,1,2,14])
        self.assertEqual(task2(data),168)

if __name__ == '__main__':
    #unittest.main()
    data = aoc.load_data(NUMBER, verbose=True)
    data = sorted(int(x) for x in data.split(','))
    print('Task1:', task1(data))
    print('Task2:', task2(data))

UPD: трохи прибрав код в task

Подякували: dot1

32 Востаннє редагувалося dot (07.12.2021 15:26:02)

Re: Advent of Code

2021#7 Py3.9.5
data = list(map(int, open("input.txt").read().split(",")))
one = list()
two = list()

for t in data:
    one.append(0)
    two.append(0)
    for f in data:
        one[-1] += abs(f - t)
        two[-1] += sum(range(1, abs(f - t) + 1))

print("Part One:", min(one))
print("Part Two:", min(two))

Tupo brutfors, kompjuternoji mitsjy vystatcylo: aby zrobyty i aby potcekaty v megax 2~3 sek.

33 Востаннє редагувалося koala (07.12.2021 21:37:02)

Re: Advent of Code

Ну тоді вже

- two[-1] += sum(range(1, abs(f - t) + 1))
+ two[-1] += (abs(f - t)*(abs(f - t) + 1)//2
Подякували: dot1

34

Re: Advent of Code

Те саме на Rust, з математикою щось у мене тепер зовсім поганенько. Там ніби Факі в бік вершини рухався, мо допоможе?

2021_7.rs
fn task<F>(crabs: &[i32], fuel: F) -> i32
where
    F: Fn(i32, i32) -> i32,
{
    let total = |pos| crabs.iter().map(|&crab| fuel(crab, pos)).sum();
    let mut pos = (crabs.last().unwrap() - crabs.first().unwrap()) / 2;
    let mut step = pos / 2;
    loop {
        let dist = total(pos);
        let dist_l = total(pos - 1);
        let dist_r = total(pos + 1);
        if dist <= dist_l && dist <= dist_r {
            return dist;
        } else if dist_r < dist {
            pos += step;
        } else {
            pos -= step;
        }
        step = std::cmp::max(1, step / 2);
    }
}

fn task1(crabs: &[i32]) -> i32 {
    task(crabs, |crab, pos| (pos - crab).abs())
}

fn task2(crabs: &[i32]) -> i32 {
    task(crabs, |crab, pos| {
        (pos - crab).abs() * ((pos - crab).abs() + 1) / 2
    })
}

fn main() {
    let input = aoc::get_input_from_ini_with_year("7", "2021").unwrap();
    let crabs: Vec<_> = input.split(',').map(|x| x.parse().unwrap()).collect();
    println!("Result1: {}", task1(&crabs));
    println!("Result2: {}", task2(&crabs));
}

35

Re: Advent of Code

2021#8, Py3.9.5
import re

data = list()

with open("input.txt") as file:
    for line in file:
        entry = ["".join(sorted(i)) for i in re.findall(r"\w+", line)]
        data.append((entry[:10], entry[10:]))

#  tttt
# l    r
# t    t
#  mmmm
# l    r
# b    b
#  bbbb

count = 0
sum = 0

for patterns, outputs in data:
    digits = dict()
    fives = list()
    sixs = list()

    # get basic numbers as 1, 4, 7, 8
    # and collect digits by segments
    for pattern in patterns:
        if len(pattern) == 2:
            digits["1"] = list(pattern)
        elif len(pattern) == 4:
            digits["4"] = list(pattern)
        elif len(pattern) == 3:
            digits["7"] = list(pattern)
        elif len(pattern) == 7:
            digits["8"] = list(pattern)
        elif len(pattern) == 5:
            fives.append(list(pattern))
        else:
            sixs.append(list(pattern))

    for one in digits["1"]:
        # get 6, rt
        for six in sixs[:]:
            if one not in six:
                digits["6"] = six
                rt = one
                sixs.remove(six)
                break
        if len(six) == 2:
            break

    # get rb
    for one in digits["1"]:
        if one is not rt:
            rb = one
            break

    # get 2, 3, 5
    for one in digits["1"]:
        for five in fives:
            if rt not in five:
                digits["5"] = five
            elif rb not in five:
                digits["2"] = five
            else:
                digits["3"] = five

    lb = (set(digits["6"]) - set(digits["5"])).pop()

    # get 0, 9
    for six in sixs:
        if lb in six:
            digits["0"] = six
        else:
            digits["9"] = six

    digits = dict(zip(["".join(i) for i in digits.values()], digits.keys()))
    numbers = str()

    for output in outputs:
        if digits[output] in ["1", "4", "7", "8"]:
            count += 1
        numbers += digits[output]
    sum += int(numbers)

print("Part One:", count)
print("Part Two:", sum)

36 Востаннє редагувалося dot (08.12.2021 14:14:08)

Re: Advent of Code

Odyn tcuvak zrobyv druhu tcastynu krasyvo. Teg tak ± podumuvav zrobyty tcerez set i issubset, ale mij tupyj mozok tcomusj tupo zatcepyv sja za «spercu sortonuty rjadok i tak trymaj!».

37

Re: Advent of Code

Я поки що обломився з другою частиною :( Часу мало.

38 Востаннє редагувалося koala (09.12.2021 01:40:50)

Re: Advent of Code

Зробив. Змусив себе. Довго, марудно і некрасиво. Можна значно краще. Але сильно ліньки.

2021/8.py
import aoc

import os

NUMBER = os.path.basename(__file__).removesuffix('.py')

DIGIT_SIZES = {0:6, 1:2, 2:5, 3:5, 4:4, 5:5, 6:6, 7:3, 8:7, 9:6}
SIZE_DIGITS = {size:[digit for digit in DIGIT_SIZES if DIGIT_SIZES[digit]==size] for size in DIGIT_SIZES.values()}


# 1 - 2, 4-4, 7-3, 8-7
# 5:
#  2&1 = 1, !2&4 = 2,  2&7 = 2
# !3&1 = 2,  3&4 = 3, !3&7 = 3
#  5&1 = 1,  5&4 = 3,  5&7 = 2
# 6:
#  0&1 = 2,  0&4 = 3,  0&7 = 3
# !6&1 = 1,  6&4 = 3, !6&7 = 2
#  9&1 = 2, !9&4 = 4,  9&7 = 3

def task1(data: str) -> int:
    result = 0
    for line in data.splitlines():
         out = line.split('|')[1].split()
         result += sum(1 for word in out if len(SIZE_DIGITS[len(word)]) == 1 )
    return result

def deduct(digit_len, known):
    if digit_len==5:
        return next({2,3,5}-set(digits.values()))
    elif digit_len==6:
        return next({0,6,9}-set(digits.values()))
    assert False

def task2(data: str) -> int:
    result = 0
    for line in data.splitlines():
        inp, out = [part.split() for part in line.split('|')]
        line = [''.join(sorted(digit)) for digit in inp+out]
        out =  [''.join(sorted(digit)) for digit in out]
        digits = {}
        for comb in line:
            if len(SIZE_DIGITS[len(comb)])==1:
                digits[comb] = SIZE_DIGITS[len(comb)][0]
                digits[SIZE_DIGITS[len(comb)][0]] = comb

        line = list({comb for comb in line if comb not in digits})
        for comb in line:
            digit = None
            if len(comb)==5:
                 if len(set(comb)&set(digits[4]))==2:
                     digit = 2
                 elif len(set(comb)&set(digits[1]))==2:
                     digit = 3
                 else:
                     digit = 5
            else: # len(comb)==6:
                 if len(set(comb)&set(digits[1]))==1:
                     digit = 6
                 elif len(set(comb)&set(digits[4]))==4:
                     digit = 9
                 else:
                     digit = 0
            if not digit is None:
                digits[comb] = digit
                digits[digit] = comb

        for comb in out:
            if not comb in digits:
                digits[comb] = deduct(len(comb), digits)
         
        result += sum(10**(3-i)*digits[out_digit] for i, out_digit in enumerate(out))
    return result
    
if __name__ == '__main__':
    data = aoc.load_data(NUMBER, verbose=True)
    print('Task1:', task1(data))
    print('Task2:', task2(data))

День 8: 1. Є 7-сегментні цифри з переплутаними контактами. Заданий набір спостережень за такими цифрами у вигляді назв сегментів (від a до g). Визначити, скільки разів вмикалися цифри 1, 4, 7, 8 (які можна визначити за відомою кількістю сегментів). 2. Серед спостережень виокремлені 4-цифрові значення. Знайти суму цих значень.

39

Re: Advent of Code

2021/9.py
import aoc

import os

NUMBER = os.path.basename(__file__).removesuffix('.py')

def task1(data: str) -> int:
    data = [[int(height) for height in line] for line in data.splitlines()]
    result = 0
    for i, line in enumerate(data):
        for j, height in enumerate(line):
            if (    (i==0              or height<data[i-1][j])
                and (j==0              or height<data[i][j-1])
                and (i==len(data)-1    or height<data[i+1][j])
                and (j==len(data[0])-1 or height<data[i][j+1])
                ):
                result += height+1
    return result

def floodfill(cave, y, x):
    if y<0 or x<0 or y==len(cave) or x==len(cave[0]) or cave[y][x]==9:
        return 0
    cave[y][x] = 9
    return (  floodfill(cave, y+1, x) + floodfill(cave, y-1, x)
            + floodfill(cave, y, x+1) + floodfill(cave, y, x-1)) + 1

def task2(data: str) -> int:
    data = [[int(height) for height in line] for line in data.splitlines()]
    basins = []
    for i in range(len(data)):
        for j in range(len(data[0])):
            basins.append(floodfill(data, i, j))
    basins.sort()
    return basins[-1]*basins[-2]*basins[-3]
    

if __name__ == '__main__':
    data = aoc.load_data(NUMBER, verbose=True)
    print('Task1:', task1(data))
    print('Task2:', task2(data))

День 9. 1. Задана прямокутна мапа висот (від 1 до 9), знайти кількість точок, нижчих за усіх свої сусідів. 2. Знайти площі найбільших зв'язних по горизонталі і вертикалі фрагментів мапи без дев'яток, повернути добуток трьох найбільших фрагментів.

Подякували: dot1

40 Востаннє редагувалося dot (09.12.2021 21:47:06)

Re: Advent of Code

2021#9
import math

heightmap = [[int(i) for i in line] for line in open("input.txt").read().split()]
lenght = len(heightmap[0])
risk = int(0)
basins = list()


def hm(c: list) -> int:
    r, s = c
    return heightmap[r][s]


def sides(r: int, c: int) -> set:
    points = set()
    if r > 0:
        points.add((r - 1, c))
    if r < len(heightmap) - 1:
        points.add((r + 1, c))
    if c > 0:
        points.add((r, c - 1))
    if c < lenght - 1:
        points.add((r, c + 1))
    return points


def low(r: int, c: int) -> bool:
    return True if hm((r, c)) < min(map(hm, sides(r, c))) else False


def basin(r: int, c: int) -> list:
    ins = {(r, c)}
    basin = {(r, c)}

    while ins:
        news = set()
        for i in ins:
            n = set()
            for s in sides(*i) - basin:
                if hm(s) > hm(i) and hm(s) != 9:
                    n.add(s)
                    basin.add(s)
            news.update(n)
        ins = news
    return basin


for r, row in enumerate(heightmap):
    for c, col in enumerate(row):
        if low(r, c):
            risk += col + 1
            basins.append(basin(r, c))

coords = list()
for b in basins:
    coords += b

class bcolors:
    OKBLUE = '\033[94m'
    ENDC = '\033[0m'

for r, row in enumerate(heightmap):
    line = str()
    for c, col in enumerate(row):
        if (r, c) in coords:
            line += bcolors.OKBLUE + str(hm((r, c))) + bcolors.ENDC
        else:
            line += str(hm((r, c)))
    print(line)

print("Part One:", risk)
print("Part Two:", math.prod(sorted(map(len, basins), reverse=True)[:3]))

Dekiljka proxolodnyx opovidok.

Perca. Pislja toho, jak ja nadislav rozvjatok poperednjoji zadatcy sjudy i v dekotryx mistsjax — vyrubyv sja internet, bo jakyjsj rozumnyk desj obrizav provid. Vtcasno ja vtcora rozvjazav zadatcku, ehe, pravda, ne vstyh zakomytyty, tomu na Qythabi vge odna typu prohalyna. Internetu ne bulo ag-no do 16 hodyny sjoʼdnja.

Druha, pro tsju zadatcu. Ja tcomusj dumav, ge susjidnja kljityna muse buty tupo na odynytsju biljce. Tomu perca vidpovidj za testom zjbihala sja, ale na tsjomu vse. Ja dectco ljinyvyj, tomu xotjiv pohljanuty na basejny vizujaljno — ctco i zrobyv. Tak i dijclo, ge riznytsja v odynytsju neobovjazkova. No i pomitno, ge rozvjatok neoptimizovanyj, bo mogna bulo vykorystaty fuktsiju z poperednjoji zadatcy.