SQL 코드 2020의 출현 – 3일 차: “Toboggan Trajectory”

17941 단어 sqladventofcode
좋아, this is a tougher one SQL에서 – 하지만 완전히 가능합니다!

우리는 반복되는 나무 패턴을 가지고 있으며 항상 아래로 1개, 오른쪽으로 3개 갈 때 왼쪽 상단 위치에서 시작하여 몇 그루의 나무를 칠 것인지 계산해야 합니다.

조금 더 쉽게 만들기 위해 PL/SQL을 사용하여 입력( )을 해당 레이아웃의 테이블로 변환합니다.



포스
나무


1
1
0

1
2
1

1

0



create table aoc_day3_input (
  line integer not null,
  pos integer not null,
  tree number(1,0) not null,
  primary key (line, pos)
);

create or replace package advent_of_code_day_3 as
  procedure load_input;
end;
/

create or replace package body advent_of_code_day_3 as
  procedure load_input as
    l_request utl_http.req;
    l_response utl_http.resp;
    l_value varchar2(1024);
    l_line integer := 1;
    l_tree number(1,0) := 0;
  begin
    execute immediate 'truncate table aoc_day3_input';
    begin
      l_request := utl_http.begin_request('http://192.168.3.102/day_3_input.txt');
      l_response := utl_http.get_response(l_request);
      loop
        utl_http.read_line(l_response, l_value, true);
        for l_pos in 1..length(l_value) loop
            if substr(l_value, l_pos, 1) = '#' then
              l_tree := 1;
            else
              l_tree := 0;
            end if;
            insert into aoc_day3_input (line, pos, tree)
              values ( l_line, l_pos, l_tree);
          end loop;
        l_line := l_line+1;
      end loop;
    exception
      when utl_http.end_of_body then
        utl_http.end_response(l_response);
    end;
  end;

end;
/

call advent_of_code_day_3.load_input();
commit;

select * from aoc_day3_input order by line, pos;


해당 데이터로 이제 recursive WITH-clauses을 사용하여 입력 데이터를 반복할 수 있습니다.

with
  max_pos as (
    select max(pos) max_pos
      from aoc_day3_input
  ),
  step( line, pos, tree) as (
    select line, pos, tree
      from aoc_day3_input
      where line = 1 and pos = 1
    union all
    select cur.line, cur.pos, cur.tree
      from aoc_day3_input cur,
           step prev,
           max_pos mp
      where cur.line = prev.line+1
        and cur.pos =
          case when prev.pos+3 > mp.max_pos then
            mod(prev.pos+3, mp.max_pos)
          else
            prev.pos+3
          end
  )
select sum(tree) from step;


패턴을 반복하려면 현재 위치가 최대 위치보다 큰지 확인해야 합니다(다른 WITH 절과 결합할 수 있는 정보). 그렇다면 나머지만 가져갑니다.

다시 요약하는 것은 SQL 덕분에 쉽습니다.

파트 2에서는 이제 두 가지 작업을 더 수행하기를 원합니다.
  • 5개의 다른 슬로프에 대해 히트 나무 계산
  • 5개 결과 모두 곱하기

  • 이것은 또한 두 가지 다른 과제입니다. 일단, 서로 다른 오른쪽/아래 값을 가진 다른 슬로프를 가져와야 합니다. 다른 WITH 절로 이것을 할 수 있습니다.

    두 번째 과제는 다른 행에 있는 결과를 곱하는 것입니다. 이를 극복하기 위해 행을 열로 피벗할 수 있으며 열을 쉽게 곱할 수 있습니다.

    with
      max_pos as (
        select max(pos) max_pos
          from aoc_day3_input
      ),
      slopes as (
        select 1 id, 1 right, 1 down from dual union all
        select 2 , 3 , 1 from dual union all
        select 3 , 5 , 1 from dual union all
        select 4 , 7 , 1 from dual union all
        select 5 , 1 , 2 from dual
      ),
      step( line, pos, tree, slope_id) as (
        select line, pos, tree, slopes.id slope_id
          from aoc_day3_input, slopes
          where line = 1 and pos = 1
        union all
        select cur.line, cur.pos, cur.tree, slope.id
          from aoc_day3_input cur,
            step prev,
            slopes slope,
            max_pos mp
          where
            slope.id = prev.slope_id
            and cur.line = prev.line+slope.down
            and cur.pos =
              case when prev.pos+slope.right > mp.max_pos then
                mod(prev.pos+slope.right, mp.max_pos)
              else
                prev.pos+slope.right
              end
      ),
      slope_results as (
        select
          slope_id, sum(tree) trees_hit
          from step
          group by slope_id
      )
    select "1"*"2"*"3"*"4"*"5"
      from slope_results 
      pivot (
        sum(trees_hit)
        for slope_id
        in (1, 2, 3, 4, 5)
      );
    


    야! 재미있었어요.

    Oracle LiveSQL 에서 파트 1과 2(입력 데이터의 처음 9줄의 스크립트 채우기 포함)를 찾을 수 있습니다.

    좋은 웹페이지 즐겨찾기