1 Востаннє редагувалося dot (10.12.2021 10:09:35)

Тема: Advent of Code

Z nazvy i za sutjoju zrozumilo, ge poxode vid Advent Calendar, ctco je takoju soboju korobkoju z 24~25 jactcykiv, kotru vidkryvajec ctcodnja z 1 hrudnja i otrymajec jakyjsj minipodarunok, perevagno tsukerku. Moʼ navitj zustrjitcaly na nepravoslavnyx ihrax, de otrymuvaly mali bonusy.

Tut, na adventofcode.com, natomistj ctcodnja znaxodec dvi vidpovidjy, aby otrymaty vidpovidno dvi zironjky. Tut nemaje obmegenj — mogna budj-jakoju movoju tcy svojym sposobom otrymuvaty vidpovidj. Jakctco otrymaly zironjky ranjice za vsjyx, to otrymujete baly i majete zmohu popasty na spysok pocany. Mogna xiba ctco zaznatcyty, ge z nastupnym dnjom vpravy stajutj skladnjicymy.

Je mistsjova docka percostjy, tam je otcky i zironjky vykonanyx vprav. Jak potrapyty: [Leaderboard] → [Private Leaderboard] → You can join a private leaderboard by entering its join code here, de vvodyte 728806-963332f3.

Vidbuvaje sja ctcoroku z 2015. Jakctco vperce potculy, to ne zasmutcujte sja, mogete vykonuvaty v budj-jakyj denj, xiba ctco ne budutj dodatkovi zhadani baly.

Tog po sutji, to zmahannja na alqoritmy. Je vidpovidna spiljnota na Redytji. Ja podumav, a tcomu ne buty ctcosj podibnoho i tut, Ukrajynsjkoju?

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

2 Востаннє редагувалося dot (01.12.2021 22:57:10)

Re: Advent of Code

Jak i kazav, percyj denj zazvytcaj duge prostenjkyj.

2021#1, Py3.9
count = 0
three = list()

with open("input.txt") as file:
    arr = [int(item) for item in file]

for i in range(1, len(arr)):
    if arr[i] > arr[i - 1]:
        count += 1

print("Part One: ", count)

count = 0

for i in range(0, len(arr) - 2):
    three.append(sum(arr[i : i + 3]))

for i in range(1, len(three)):
    if three[i] > three[i - 1]:
        count += 1

print("Part Two: ", count)
Подякували: koala1

3 Востаннє редагувалося koala (01.12.2021 23:52:06)

Re: Advent of Code

aoc.py
import requests

DATA_FILE_NAME = '{}.txt'
AOC_URL = 'https://adventofcode.com/2021/day/{}/input'
SESSION = 'PASTE-IT-HERE'

def load_data(number: str, *, verbose: bool = False) -> str:

    def log(*args, **kwargs):
        if verbose:
            print(*args, **kwargs)
            
    filename = DATA_FILE_NAME.format(number)
    try:
        with open(filename) as file:
            log(f"Cached data found, reading {filename}")
            return file.read()
    except OSError:
        log(f"Cached data in {filename} not found")
    url = AOC_URL.format(number)
    cookies = {'session':SESSION}
    log(f"Sending request to {url}")
    request = requests.get(url, cookies=cookies)
    request.raise_for_status()
    log(f"Data revieved")
    with open(filename, 'w') as file:
        log(f"Caching retrieved {len(request.text)} bytes to {filename}")
        file.write(request.text)
    return request.text
2021/1.py
import aoc

import os
 
def task1(data: str) -> int:
    depths = [int(depth) for depth in data.split()]
    return sum(1 for a, b in zip(depths, depths[1:]) if a<b)

def task2(data: str) -> int:
    depths = [int(depth) for depth in data.split()]
    sliding_windows = [sum(depths[i:i+3]) for i in range(len(depths)-2)]
    return sum(1 for a, b in zip(sliding_windows, sliding_windows[1:]) if a<b)

if __name__ == '__main__':
    data = aoc.load_data(os.path.basename(__file__).removesuffix('.py'), verbose=True)
    print(task1(data))
    print(task2(data))

Понова: додав параметр verbose для load_data, так красивіше.

Зразок виводу
Cached data in 1.txt not found
Sending request to https://adventofcode.com/2021/day/1/input
Data revieved
Caching retrieved 9775 bytes to 1.txt
1390
1457
Подякували: dot, leofun012

4 Востаннє редагувалося dot (02.12.2021 09:15:21)

Re: Advent of Code

Kruto, ctce odyn Pajtonist, mo' bude z tcym porivnjuvaty i navitj povtcyty sja u svojoho.

2021#2, Py3.9.5
commands = {
    "forward": 0,
    "up": 0,
    "down": 0,
}

with open("input.txt") as file:
    for line in file:
        position, number = line.split()
        commands[position] += int(number)

print("Part One:", commands["forward"] * (commands["down"] - commands["up"]))

aim = 0
depth = 0
forward = 0

with open("input.txt") as file:
    for line in file:
        position, number = line.split()
        number = int(number)

        if position == "forward":
            forward += number
            depth += aim * number
        else:
            aim += number if position == "down" else -number


print("Part Two:", forward * depth)

Ex, ljinjky meni vvantagyty 3.10, tam je podoba do switch.

5 Востаннє редагувалося koala (02.12.2021 10:10:25)

Re: Advent of Code

2021/2.py. Через одрук довелося тести додавати
import aoc

import os
import unittest

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

def task1(data: str) -> int:
    SHIFTS = {'forward':(1,0),'up':(0,-1),'down':(0,1)}
    x, y = 0, 0
    for command in data.splitlines():
        command, argument = command.split()
        value = int(argument)
        dx, dy = SHIFTS[command]
        x, y = x+dx*value, y+dy*value
    return x*y
        

def task2(data: str) -> int:
    SHIFTS = {'forward':(1,1,0),'up':(0,0,-1),'down':(0,0,1)}
    x, y, aim = 0, 0, 0
    for command in data.splitlines():
        command, argument = command.split()
        value = int(argument)
        dx, dy, da = SHIFTS[command]
        x, y, aim = x + dx*value, y + dy*aim*value, aim + da*value
    return x*y

class TestDay2(unittest.TestCase):
    def test_task2(self):
        data = '''forward 5
down 5
forward 8
up 3
down 8
forward 2'''
        self.assertEqual(task2(data), 900, 'Example failed')

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

У вашому способі collections.defaultdict міг би зекономити пару рядків.

Якщо хтось іще зацікавиться, наведу завдання українською (без обгортки про підводний човен Санти). Кожного дня 2 завдання зі спільними даними, 2 відкривається, якщо навести правильну відповідь на 1.
День 1. 1. Є ряд чисел, треба знайти, скільки разів відбувається збільшення відносно попереднього.
2. Те саме для суми по ковзному вікну довжиною 3.
День 2. 1. Є набір команд "вперед, вгору, вниз" (для підводного човна, ага). Рух починається з (0,0). Треба знайти добуток кінцевих координат.
2. Інша інтерпретація команд: є третій параметр човна, "ціль". "Вгору" та "вниз" зменшують і збільшують ціль, "вперед X" рухає горизонтально на X і вглиб на X*ціль. Знайти добуток кінцевих координат.

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

6 Востаннє редагувалося koala (03.12.2021 01:40:26)

Re: Advent of Code

На Rust перше навіть лаконічніше. І зверніть увагу на 1.2 - ми цей момент пропустили, а Rust якось ненав'язливо до нього примусив :)

2021_1.rs
fn task1(depths: &[u32]) -> usize
{
    depths.windows(2)
          .filter(|&w|w[0]<w[1])
          .count()
}

fn task2(depths: &[u32]) -> usize
{
    depths.windows(4)
         .filter(|&w|w[0]<w[3])
         .count()

}

fn main() {
    let input = aoc::get_input_from_ini_with_year("1","2021").unwrap();
    let depths:Vec<_> = input.lines()
                             .map(|line|line.parse::<u32>().unwrap())
                             .collect();
    println!("Result1: {}", task1(&depths));
    println!("Result2: {}", task2(&depths));
}
2021_2.rs
enum Command {
    Forward(i32),
    Down(i32),
    Up(i32)
}

impl Command {
    fn new(line: &str) -> Command
    {
        let mut parts = line.split_whitespace();
        let instruction  = parts.next().unwrap();
        let value = parts.next().unwrap().parse().unwrap();
        use Command::*;
        match instruction {
            "forward" => Forward(value),
            "down"    => Down(value),
            "up"      => Up(value),
            _         => panic!("{}", instruction)
        }
    }
}

fn task1(commands: &[Command]) -> i32
{
    use Command::*;
    let (x, y) = commands.iter()
                       .fold((0,0),|(x,y), command|match command {
                        Forward(dx) => (x+dx, y),
                        Down(dy)    => (x,    y+dy),
                        Up(dy)      => (x,    y-dy)
                       });
    x*y
}

fn task2(commands: &[Command]) -> i32
{
    use Command::*;
    let (x, y, _) = commands.iter()
                          .fold((0,0,0),|(x,y,aim), command|match command {
                            Forward(v) => (x+v, y+aim*v, aim),
                            Down(da)   => (x,   y,       aim+da),
                            Up(da)     => (x,   y,       aim-da)
                           });
    x*y
}

fn main() {
    let input = aoc::get_input_from_ini_with_year("2","2021").unwrap();
    let commands:Vec<_> = input.lines()
                                .map(|line|Command::new(line))
                             .  collect();
    println!("Result1: {}", task1(&commands));
    println!("Result2: {}", task2(&commands));
}
Подякували: dot, leofun012

7

Re: Advent of Code

2021/3.py
import aoc

import os
import unittest

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

def task1(data: str) -> int:
    numbers = data.splitlines()
    counter = [sum(int(n[i]) for n in numbers) for i in range(len(numbers[0]))]
    gamma = epsilon = ''
    for i, c in enumerate(counter):
        if c>len(numbers)/2:
            gamma += '1'
            epsilon += '0'
        else:
            gamma += '0'
            epsilon += '1'
        
    return int(gamma,2)*int(epsilon,2)
        

def task2(data: str) -> int:
    numbers = data.splitlines()
    oxygen = numbers[:]
    for i in range(len(numbers[0])):
        counter = sum(int(n[i]) for n in oxygen)
        oxygen = [number for number in oxygen if (number[i]=='1')==(counter>=len(oxygen)/2)]
        if len(oxygen)==1:
            break
    co2 = numbers[:]
    for i in range(len(numbers[0])):
        counter = sum(int(n[i]) for n in co2)
        co2 = [number for number in co2 if (number[i]=='0')!=(counter<len(co2)/2)]
        if len(co2)==1:
            break

    return int(oxygen[0],2)*int(co2[0],2)
    

class TestDay3(unittest.TestCase):
    def test_task2(self):
        data = '''00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010'''
        self.assertEqual(task2(data), 230, 'Example failed')

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

Щось з умовами перемудрив, але працює.

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

8

Re: Advent of Code

День 3. 1. Є набір двійкових чисел однакової довжини (але можуть починатися з 0). Треба знайти добуток двох характеристик. Перша характеристика має на i-й позиції найчастішу цифру на i-й позиції у числах з набору, друга - менш часту.
2. Ті самі числа, але процедура інша. Викидаємо всі числа, у яких на першій позиції не найчастіша цифра; далі, всі, де на другій позиції не найчастіша у залишку і т.д., поки не залишиться одне число, це і буде перша характеристика. Якщо однаково - лишається 1. Друга характеристика - так само за рідшою цифрою, якщо однаково - 0. Знову ж таки добуток.

9 Востаннє редагувалося dot (03.12.2021 18:54:20)

Re: Advent of Code

2021#3 Py3.9.5
with open("input.txt") as file:
    diagnostic = [[int(i) for i in line.strip()] for line in file]

γ = list()
ε = list()

for i in zip(*diagnostic):
    most = max(i, key=i.count)
    γ.append(str(most))
    ε.append(str(abs(most - 1)))

print("Part One:", int("".join(ε), 2) * int("".join(γ), 2))


def bit_criteria(variation: str) -> int:
    variation = 1 if variation == "oxygen" else 0
    rating = diagnostic.copy()

    for l in range(len(list(zip(*diagnostic)))):
        bit = list()

        for i in rating[:]:
            bit.append(i[l])

        ones = bit.count(1)
        zeros = bit.count(0)

        if ones == zeros:
            number = 1 if variation else 0
        elif ones > zeros:
            number = 1 if variation else 0
        else:
            number = 0 if variation else 1

        for k in rating[:]:
            if k[l] != number:
                rating.remove(k)

        if len(rating) == 1:
            rating = rating[0]
            break

    return int("".join([str(i) for i in rating]), 2)


print("Part Two:", bit_criteria("oxygen") * bit_criteria("carbon dioxide"))

10 Востаннє редагувалося dot (03.12.2021 21:10:15)

Re: Advent of Code

Ne moje, ale pobatcyv take i typu zʼoqrazmyv:

2021#3,1
r = *map(str.strip,open(0)),
F = lambda f: int(''.join([f(x, key=x.count) for x in zip(*r)]), 2)
print(F(max) * F(min))

Desj v mojomu naprjamku, bo teg tcerez max i zip, ale korotce i krasyvice.

11

Re: Advent of Code

День 4. 1. Гра Бінго. Є послідовність чисел і послідовність полів 5x5. Числа називаються по одному, коли число назване, його викреслюють з усіх полів. Визначити, на якому полі першому виникне рядок чи стовпчик із 5-и викреслених чисел і обчислити добуток невикреслених чисел на останнє назване число на цьому полі.
2. Те саме, тільки останнє поле, на якому буде викреслений стовпчик чи рядок.

2021/4.py
import aoc

import os

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

class Bingo:
    def __init__(self, data:str):
        data = data.splitlines()
        self.numbers = [int(x) for x in data[0].split(',')]
        self.boards = []
        for line in data[1:]:
            if not line.strip():
                self.boards.append([])
            else:
                self.boards[-1].append([int(x) for x in line.split()])
        self.strikedout = [[[False for _ in line] for line in board] for board in self.boards]
        self.winners = []

    def strikeout(self, n: int):
        for board_idx, board in enumerate(self.boards):
            for line_idx, line in enumerate(board):
                if n in line:
                    self.strikedout[board_idx][line_idx][line.index(n)] = True
                    self.check_winner(board_idx)

    def check_winner(self, idx: int):
        if idx in self.winners:
            return
        board = self.strikedout[idx]
        for line in board:
            if all(line):
                self.winners.append(idx)
                return
        for i in range(len(board[0])):
            if all(line[i] for line in board):
                self.winners.append(idx)
                return

    def score(self, idx: int, n: int) -> int:
        board = self.boards[idx]
        sboard = self.strikedout[idx]
        s = 0
        for line, sline in zip(board, sboard):
            for field, sfield in zip(line, sline):
                if not sfield:
                    s += field
        return s*n

    def task(self, criterion) -> int:
        for n in self.numbers:
            self.strikeout(n)
            if criterion(self):
                result = self.score(self.winners[-1], n)
                self.strikedout = [[[False for _ in line] for line in board] for board in self.boards]
                return result
        result = self.score(self.winners[-1], self.numbers[-1])
        self.strikedout = [[[False for _ in line] for line in board] for board in self.boards]
        return result

    def task1(self) -> int:
        return self.task(lambda b:b.winners)

    def task2(self) -> int:
        return self.task(lambda b:len(b.winners)==len(b.boards))


if __name__ == '__main__':
    board = Bingo(aoc.load_data(NUMBER, verbose=True))
    print('Task1:', board.task1())
    print('Task2:', board.task2())
Подякували: dot1

12

Re: Advent of Code

2021#4, Py3.9.5
from collections import defaultdict
from itertools import chain

lines = [i.strip() for i in open("input.txt")]

boards = defaultdict(list)
b = 0

for i in range(2, len(lines)):
    if not lines[i]:
        b += 1
        continue

    boards[b].append(list(map(int, lines[i].split())))

for board in boards:
    boards[board] += list(zip(*boards[board]))

numbers = list(map(int, lines[0].split(",")))


def task(boards: list) -> list:
    scores = list()
    marked = numbers[:4]
    for number in numbers[4:]:
        marked.append(number)
        for board in list(boards):
            for b in boards[board]:
                if set(b).issubset(marked):
                    scores.append(sum(set(chain(*boards[board])) - set(marked)) * marked[-1])
                    boards.pop(board)
    return scores


print("Part One:", task(boards.copy())[0])
print("Part Two:", task(boards.copy())[-2])

13

Re: Advent of Code

koala написав:

День 4. 1. Гра Бінго. Є послідовність чисел і послідовність полів 5x5. Числа називаються по одному, коли число назване, його викреслюють з усіх полів. Визначити, на якому полі першому виникне рядок чи стовпчик із 5-и викреслених чисел і обчислити добуток невикреслених чисел на останнє назване число на цьому полі.
2. Те саме, тільки останнє поле, на якому буде викреслений стовпчик чи рядок.

2021/4.py
import aoc

import os

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

class Bingo:
    def __init__(self, data:str):
        data = data.splitlines()
        self.numbers = [int(x) for x in data[0].split(',')]
        self.boards = []
        for line in data[1:]:
            if not line.strip():
                self.boards.append([])
            else:
                self.boards[-1].append([int(x) for x in line.split()])
        self.strikedout = [[[False for _ in line] for line in board] for board in self.boards]
        self.winners = []

    def strikeout(self, n: int):
        for board_idx, board in enumerate(self.boards):
            for line_idx, line in enumerate(board):
                if n in line:
                    self.strikedout[board_idx][line_idx][line.index(n)] = True
                    self.check_winner(board_idx)

    def check_winner(self, idx: int):
        if idx in self.winners:
            return
        board = self.strikedout[idx]
        for line in board:
            if all(line):
                self.winners.append(idx)
                return
        for i in range(len(board[0])):
            if all(line[i] for line in board):
                self.winners.append(idx)
                return

    def score(self, idx: int, n: int) -> int:
        board = self.boards[idx]
        sboard = self.strikedout[idx]
        s = 0
        for line, sline in zip(board, sboard):
            for field, sfield in zip(line, sline):
                if not sfield:
                    s += field
        return s*n

    def task(self, criterion) -> int:
        for n in self.numbers:
            self.strikeout(n)
            if criterion(self):
                result = self.score(self.winners[-1], n)
                self.strikedout = [[[False for _ in line] for line in board] for board in self.boards]
                return result
        result = self.score(self.winners[-1], self.numbers[-1])
        self.strikedout = [[[False for _ in line] for line in board] for board in self.boards]
        return result

    def task1(self) -> int:
        return self.task(lambda b:b.winners)

    def task2(self) -> int:
        return self.task(lambda b:len(b.winners)==len(b.boards))


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

Oho, tcerez klasy i funtsijy, potugno.

14

Re: Advent of Code

Мені пам'яті не вистачає на третій вкладений цикл. Власної, не комп'ютерної. А тут усе тупо моделюється, як в умові написано, думати не треба.

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

15

Re: Advent of Code

Зовсім трохи бітової арифметики.

2021_3.rs
fn task1(numbers: &[usize], size: usize) -> usize
{
    let (gamma, epsilon) = (0..size).rev()
                                    .map(|i|numbers.iter()
                                                   .filter(|&n|(n>>i)&1==1)
                                                   .count())
                                    .fold((0,0),|(gamma, epsilon), count|
                                    (
                                        (gamma  <<1) | (2*count> numbers.len()) as usize, 
                                        (epsilon<<1) | (2*count<=numbers.len()) as usize,
                                    ));
    gamma*epsilon
}

fn find_by_bit_criteria<F>(numbers: &[usize], size: usize, criteria: F) -> usize
    where F: Fn(usize, bool) -> bool
{
    let mut numbers = Vec::from(numbers);
    for i in (0..size).rev() {
        if numbers.len() == 1 {
            break;
        }
        let more_ones = numbers.iter()
                               .filter(|&n|(n>>i)&1==1)
                               .count()*2 >= numbers.len();
        numbers = numbers.into_iter()
                         .filter(|&n|criteria((n>>i)&1, more_ones))
                         .collect();
    }
    numbers[0]
}

fn task2(numbers: &[usize], size: usize) -> usize
{
    let oxygen = find_by_bit_criteria(numbers, size, 
        |digit, more_ones| (digit == 1) == more_ones);
    let co2 = find_by_bit_criteria(numbers, size, 
        |digit, more_ones| (digit == 0) == more_ones);
    oxygen * co2
}

fn main() {
    let input = aoc::get_input_from_ini_with_year("3","2021").unwrap();
    let mut size = 0;
    let numbers:Vec<_> = input.lines()
                              .map(|line|{size=line.len();usize::from_str_radix(line, 2).unwrap()})
                              .collect();
    println!("Result1: {}", task1(&numbers, size));
    println!("Result2: {}", task2(&numbers, size));
}

Rust не відпускає, доки не доведеш запис до ідеалу. Умову я десь годину оптимізовував, додавав і викидав Ordering і т.д. Зате яка краса в результаті.

Подякували: dot, leofun012

16

Re: Advent of Code

А оце я щось розійшовся. І Rust не допоміг :(
Працює, звісно, але шукав тупу помилку дуже довго.

2021_4.rs
const BINGO_SIZE :usize = 5;

struct Board ([[usize; BINGO_SIZE];BINGO_SIZE] );

impl Board {
    fn position(&self, value: usize) -> Option<(usize, usize)> {
        for row in 0..BINGO_SIZE {
            for col in 0..BINGO_SIZE {
                if self.0[row][col] == value {
                    return Some((row, col));
                }
            }
        }
        None
    }
}

struct BingoSettings
{
    calls: Vec<usize>,
    boards: Vec<Board>,
}

impl BingoSettings
{
    fn from_str(s: &str) -> BingoSettings {
        let mut s = s.lines();
        let calls = s.next()
                     .unwrap()
                     .split(",")
                     .map(|s|s.parse().unwrap())
                     .collect();
        let mut boards = Vec::new();
        let mut idx = 0;
        for line in s {
            if line.is_empty() {
                boards.push(Board([[0, 0, 0, 0, 0, ],
                                   [0, 0, 0, 0, 0, ],
                                   [0, 0, 0, 0, 0, ],
                                   [0, 0, 0, 0, 0, ],
                                   [0, 0, 0, 0, 0, ],]));
                idx = 0;
            } else {
                let mut board = boards.last_mut().unwrap();
                for (i, n) in line.split_whitespace().enumerate() {
                    board.0[idx][i] = n.parse().unwrap();
                }
                idx = (idx+1) % 5;
            }
        }
        BingoSettings {
            calls,
            boards,
        }
    }
}

type StrikeBoard = [[bool; BINGO_SIZE];BINGO_SIZE];

struct Bingo<'a>
{
    settings: &'a BingoSettings,
    winners: Vec<(usize, usize)>,
    striked: Vec<StrikeBoard>,
}

impl Bingo<'_>
{
    fn new(settings: &BingoSettings) -> Bingo
    {
        Bingo {
            settings,
            winners: Vec::new(),
            striked: std::iter::repeat([[false, false, false, false, false, ],
                                        [false, false, false, false, false, ],
                                        [false, false, false, false, false, ],
                                        [false, false, false, false, false, ],
                                        [false, false, false, false, false, ],])
            .take(settings.boards.len())
            .collect(),
        }
    }

    fn task(&mut self, nwinner:usize) -> usize {
        for &call in &self.settings.calls {
            self.strikeout(call);
            if self.winners.len() == nwinner {
                break;
            }
        }
        self.last_winner_score()
    }

    fn strikeout(&mut self, call: usize) {
        for board_idx in 0..self.striked.len() {
            if let Some((row, col)) = self.settings.boards[board_idx].position(call) {
                self.striked[board_idx][row][col] = true;
                self.check_winner(board_idx, row, col, call);
            };
        }
    }

    fn check_winner(&mut self, board_idx:usize, row_idx: usize, col_idx:usize, call: usize)
    {
        if !self.winners.iter().find(|&&(board, _)|board == board_idx).is_some() {
            if     (0..BINGO_SIZE).map(|i|self.striked[board_idx][row_idx][i])
                                  .all(|striked|striked)
                || (0..BINGO_SIZE).map(|i|self.striked[board_idx][i][col_idx])
                                  .all(|striked|striked) {
                let mut score = 0;
                for row in 0..BINGO_SIZE {
                    for col in 0..BINGO_SIZE {
                        if !self.striked[board_idx][row][col] {
                            score += self.settings.boards[board_idx].0[row][col];
                        }

                    }
                }
                self.winners.push((board_idx, call * score));
            }
        }
    }

    fn last_winner_score(&self) -> usize {
        self.winners.last().unwrap().1
    }
}

fn task1(bingo: &BingoSettings) -> usize
{
    Bingo::new(bingo).task(1)
}

fn task2(bingo: &BingoSettings) -> usize
{
    Bingo::new(bingo).task(bingo.boards.len())
}

#[cfg(test)]
mod tests {
    // Note this useful idiom: importing names from outer (for mod tests) scope.
    use super::*;
    const DATA: &str = "7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1

22 13 17 11  0
 8  2 23  4 24
21  9 14 16  7
 6 10  3 18  5
 1 12 20 15 19

 3 15  0  2 22
 9 18 13 17  5
19  8  7 25 23
20 11 10 24  4
14 21 16 12  6

14 21 17 24  4
10 16 15  9 19
18  8 23 26 20
22 11 13  6  5
 2  0 12  3  7";

    #[test]
    fn test_task1() {
        let bingo = BingoSettings::from_str(&DATA);
        assert_eq!(task1(&bingo), 4512);
    }


    #[test]
    fn test_task2() {
        let bingo = BingoSettings::from_str(&DATA);
        assert_eq!(task2(&bingo), 1924);
    }
}

fn main() {
    let input = aoc::get_input_from_ini_with_year("4","2021").unwrap();
    let bingo = BingoSettings::from_str(&input);
    println!("Result1: {}", task1(&bingo));
    println!("Result2: {}", task2(&bingo));
}

17

Re: Advent of Code

Спершу хотів погратися з інтервалами, потім вирішив, що 1000х1000 - не надто велике поле.

2021/5.py
import aoc

import os

NUMBER = os.path.basename(__file__).removesuffix('.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:
    field = [[0]*1000 for _ in range(1000)]
    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:
            field[x][y] += 1
            if [x,y]==line[1]:
                break
            x += dx
            y += dy
    return sum(1 for line in field for vent in line if vent>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))
Подякували: dot1

18 Востаннє редагувалося koala (05.12.2021 11:21:51)

Re: Advent of Code

А до біса, Rust так само:

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

const FIELD_SIZE: usize = 1000;

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
{
    let mut field: Vec<Vec<i32>> = std::iter::repeat(std::iter::repeat(0).take(FIELD_SIZE).collect()).take(FIELD_SIZE).collect();
    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 {
                field[x as usize][y as usize] += 1;
                if (x,y) == vent.1 {
                    break;
                }
                x += dx;
                y += dy;
            }
        }
    }
    field.iter().map(|line|line.iter().filter(|&&x|x>1).count() as i32).sum()
}

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));
}
Подякували: dot1

19 Востаннє редагувалося dot (05.12.2021 13:05:09)

Re: Advent of Code

2021#5 Py3.9.5
import re, itertools

vents = list()

with open("input.txt") as file:
    for line in file:
        x1, y1, x2, y2 = map(int, re.findall(r"\d+", line))
        xo = 1 if x1 <= x2 else -1
        yo = 1 if y1 <= y2 else -1

        # For Part One
        # if x1 == x2 or y1 == y2:

        for x, y in itertools.zip_longest(
            range(x1, x2 + xo, xo),
            range(y1, y2 + yo, yo),
            fillvalue=x1 if x1 == x2 else y1 if y1 == y2 else None,
        ):
            vents.append((x, y))

overlaps = {}

for e in vents:
    overlaps[e] = overlaps.get(e, 0) + 1

points = 0

for _, o in overlaps.items():
    if o > 1:
        points += 1

print("Answer:", points)  # 7436, 21104

Ja vzahalji obijcov sja bez matritsjy, tupo tcerez spyskiv koordynat, qeq. Ja navitj tcomusj, nespodjivano dlja sebe, zadovolenyj svojym rezultatom — vse vidnosno lehko tcytaljno, bez gaxlyvyx perenasytcenj dugok (jakctco propustyty movu pro efektivnistj).

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

Re: Advent of Code

Модифікував

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)