Ruby 3.0의 출시 03일째 썰매 궤도

24386 단어 adventofcoderuby
Ruby 3.0이 출시된 지 얼마 되지 않아 1년 중 가장 즐거운 시기입니다. 우리는 어떤 재미있는 새로운 기능이 있는지 시험해 보도록 하겠습니다.
이 시리즈에서는 Ruby 2.7 및 3.0의 몇 가지 기능과 사용 방법solve Advent of Code problems에 대해 설명합니다.해결 방안 자체가 가장 효과적이라는 뜻이 아니라 기능의 새로운 용도를 보여줘야 한다.
나는 이 문장들을 날짜별로 분류할 것이다. 왜냐하면 매 문장은 점점 길어지고 그 안에 관련되기 때문에 나는 10분 이상의 문장을 자주 발표하는 것을 좋아하지 않는다.
여기까지 말하고 시작합시다!
|

Day 03-제01부분-눈썰매 궤도
나는 이 점을 이해하는 데 약간의 시간이 걸렸다.우리 지도에는 나무(#와 공백.:
..#..#
..#..#
.#..#.
우리의 썰매는 왼쪽 상단에서 시작하는데 첫 번째 부분의 경사도13를 초과하거나 1방향y방향과3방향x방향이다.X는 나무가 충돌한 것을 감안하면O은 광활한 공간이다. 우리는 우리의 썰매가 비탈길에서 활주하는 것을 볼 수 있다.
O.#..#
..X..#
.#..#O
이런 상황에서 우리는 나무에 부딪혔지만, 만약 우리가 경계를 넘었다면?보아하니 그들의 지도는 무한히 중복된 것 같아서 한 선이 ..#이면 중복된다. 예를 들어 ..#..#..#..# 등이다.
솔루션부터 시작해 보겠습니다. 여기서부터 시작하겠습니다.
SLOPE = [3, 1]
SLOPE_X, SLOPE_Y = SLOPE

TREE = '#'

def collision_count(map, slope_x: SLOPE_X, slope_y: SLOPE_Y)
  map_modulo = map.first.strip.size
  pos_x, pos_y = 0, 0

  map[1..-1].reduce(0) do |trees_hit, line|
    pos_x, pos_y = pos_x + slope_x, pos_y + slope_y
    relative_x   = pos_x % map_modulo

    line[relative_x] == TREE ? trees_hit + 1 : trees_hit
  end
end

File.readlines(ARGV[0]).then { puts collision_count(_1) }

상수
처음 행에서는 기본값에 대해 몇 가지 상수만 설정하고 나중에 사용할 값의 이름을 지정합니다.
SLOPE = [3, 1]
SLOPE_X, SLOPE_Y = SLOPE

TREE = '#'
이 줄, 특히 나의 작은 습관은 상수를 kwargs와 함께 좋은 기본값으로 명명하는 데 사용한다.
def collision_count(map, slope_x: SLOPE_X, slope_y: SLOPE_Y)
설정할 수 있는 곳으로 만들지만, 정상적인 명칭 기본값을 가지고 있습니다.이런 상황에서 경사율은 고정적이지만 장래에는 그렇지 않을 수도 있다. 이것은 우리가 필요할 때 조정할 수 있게 한다.

모형
수학은 절대 우리의 친구, 모함수에 관한 것이다.익숙하지 않은 모드에 대해 나눗셈 후의 나머지를 제시하기 때문에 다음과 같다.
10 % 10 == 0
10 % 15 == 5
10 % 25 == 5
25 안 줘요15?10는 깨끗하게 두 부분으로 나눌 수 있고 나머지515는 같기 때문이다.
이것은 시리즈를 순환하고 순환하는 데 매우 유용하며, 이 예에서는 무한히 오른쪽으로 뻗은 스티커입니다.이것이 바로 이 말이 왜 매우 유용한지 우리에게 단점이 어디에 있는지 알려줄 수 있다.
map_modulo = map.first.strip.size

낙하산.
이 감소를 살펴보겠습니다. 잠시 후에 우리는 재미있는 견해를 가지고 있을 것입니다.
pos_x, pos_y = 0, 0

map[1..-1].reduce(0) do |trees_hit, line|
  pos_x, pos_y = pos_x + slope_x, pos_y + slope_y
  relative_x   = pos_x % map_modulo

  line[relative_x] == TREE ? trees_hit + 1 : trees_hit
end
우선 당신은 map[1..-1]를 주의하게 될 것입니다. 이것은 첫 번째 줄이 우리와 무관하기 때문입니다. 왜냐하면 문제에 따라 썰매는 항상 깨끗한 곳에서부터 시작하기 때문입니다.
우리는 여기서 초기치reduce0를 사용하여 우리가 불행하게 만난 나무의 총수를 누적한다.
map[1..-1].reduce(0) do |trees_hit, line|
우리가 먼저 알아야 할 것은 우리의 입장이다.위의 첫 줄에서 우리는 xy0로 시작 위치로 설정할 것이다.이 길드는 경사도에 따라 업데이트됩니다.
pos_x, pos_y = pos_x + slope_x, pos_y + slope_y
우리는 y 위치를 실제로 사용하지 않았지만, 나는 그것이 잠시 후에 나타날 것이라고 확신한다. 그래서 우리는 범위에 따라 업데이트를 진행할 수 있다.
이 부분의 진정한 문제는 우리가 무한지도상의 위치에 있다는 것이다.모형 기억나세요?우리는 그것으로 우리가 앞에서 알고 있는 지도상의 상대적인 위치를 얻을 수 있다.
relative_x = pos_x % map_modulo
그래서 만약에 우리가 x30에서 출발하면 지도는 12개 단위장만 있고 우리의 친척x6이거나 30 % 12인 것을 알 수 있다.
일단 우리가 지도에 대한 위치를 알게 되면 그곳에 나무가 있는지 물어볼 수 있다.
line[relative_x] == TREE
있는 경우 카운트에 하나를 추가하거나 현재 카운트를 반환하고 다음 행을 확인합니다.
line[relative_x] == TREE ? trees_hit + 1 : trees_hit

우리 오랜 친구
이것은 아주 비슷한 선 하나만 남았다.
File.readlines(ARGV[0]).then { puts collision_count(_1) }
...우리는 우리의 해결 방안이 있다.

3일째 - 2부 - 각도가 뭐예요?
위에서 우려한 바와 같이, 사율이 바뀔 수 있다. y 의 사율을 포함해서. 이것은 간단한 교체가 더 이상 효과가 없다는 것을 의미한다.하지만 두려워하지 마세요. 루비는 이 문제를 상당히 간단하게 만들 수 있는 재미있는 기교가 있으니까요.

차근차근
우리는 깨끗하게 교체할 수 없기 때문에, 우리는 반드시 다른 해결 방안을 찾아야 한다.
...아니면 우리?만약 루비에게 이런 상황을 겨냥한 도구가 있다면?이것은 step 또는 업데이트% 범위 연산자로 불린다.
(1..10).step(3).to_a
# => [1, 4, 7, 10]

((1..10) % 3).to_a
# => [1, 4, 7, 10]
%의 우선촬영..이 범위에 적용되기 때문에 이렇게 하지 마십시오.
(1..10 % 3).to_a
# => [1]
...10 % 31이기 때문에 현재의 범위는1..1이다.
어쨌든 나는 step을 선택하는 경향이 있다. 왜냐하면 그것은 더욱 뚜렷하지만 그 존재가 매우 좋다는 것을 알고 있기 때문이다.
이 모든 것을 감안하여 우리는 map 범위를 이 범위로 바꿀 수 있다. 우리는 y1보다 크다고 해석할 수 있다.
map[(slope_y..map.size) % slope_y]

긁어모으다
Ruby는 이 점을 상당히 간단하게 만들었다. 우리의 주함수의 유일한 진정한 변화는 다음과 같다.
def collision_count(map, slope_x: SLOPE_X, slope_y: SLOPE_Y)
  map_modulo   = map.first.strip.size
  pos_x, pos_y = 0, 0

  map[(slope_y..map.size) % slope_y].reduce(0) do |trees_hit, line|
    pos_x, pos_y = pos_x + slope_x, pos_y + slope_y
    relative_x   = pos_x % map_modulo

    line[relative_x] == TREE ? trees_hit + 1 : trees_hit
  end
end
다섯 번째 줄만 마지막에 바뀌었어, 대단해!

입력
유일한 또 다른 차이점은 우리가 우리의 독선을 약간 바꾸었다는 것이다.
POSITIONS = [
  { slope_x: 1, slope_y: 1 },
  { slope_x: 3, slope_y: 1 },
  { slope_x: 5, slope_y: 1 },
  { slope_x: 7, slope_y: 1 },
  { slope_x: 1, slope_y: 2 }
]

File.readlines(ARGV[0]).then do |map|
  puts POSITIONS
    .map { |pos| collision_count(map, **pos) }
    .reduce(1, :*)
end
우리는 위치 조정 목록을 보여 주고 지도에 비추어 우리가 성공한 나무의 수를 얻은 다음에AoC의 프로그램 규범에 따라 그것들을 모두 곱하기만 하면 된다.
이제 저희가 1부와 2부를 완성했습니다!

03일째 - 병행성과 반군에 대한 추가 사고
근데 여기 재미있는 패턴이 있어요.추가 고려 사항:
  • 두 개의 숫자를 더하면 한 개의 숫자를 얻을 수 있다
  • 만약 네가 0를 어떤 숫자에 더하면 그 숫자
  • 를 얻을 수 있다.
  • 숫자를 자유롭게 조합하여 같은 결과를 얻을 수 있습니다.a + b + c == (a + b) + c == a + (b + c)
  • 당신은 반전으로 모든 조작을 취소할 수 있습니다. 예를 들어 1 + -1 추가 취소1
  • 귀신이 곡할 노릇이다. 어떤 순서로든 추가할 수 있다. 그것들은 여전히 유효하다. 1 + 2 + 3 == 2 + 3 + 1 == 3 + 2 + 1
  • 이러한 속성을 규칙이라고 합니다.세 번째 규칙을 따르는 것은 모두 반군(또는 약속군, 또는 한 가지 일로)이라고 불린다. 네 번째 규칙을 더하면 군을 얻고, 다섯 번째 규칙을 더하면 아벨군을 얻는다.
    Wikipedia covers some of this하지만 이제 우리는 덧셈이 하나의 교환군이라는 것을 기쁘게 보게 될 것이다. 이것은 병행이 매우 쉽다는 것을 의미하기 때문이다.
    xy에서 내보내기 가능
    우리는 우리의 slope_x 위치와 사율을 통해 상대적x 위치를 얻을 수 있다.
    map_boundary = map_line.size - 1
    position = (y * slope_x) % map_boundary
    
    이것은 우리가 필요로 하는 물건을 찾기 위해 엄격하게 그것들을 교체할 필요가 없다는 것을 의미한다.

    나무의 총 명중수를 찾는 것은 정수 덧셈이다
    너는 나무 한 그루에 부딪히든지, 이것은 너에게 줄 것이다. y, 아니면 네가 부딪히지 않았든지, 이것은 너에게 빈 것을 줄 것이다. + 1이것은 운행하는 모든 병렬 라인에서 한 라인이 되돌아오는지 0 또는 1 를 찾아내 주 라인의 운행 총수에 추가할 수 있다는 것을 의미한다.
    그렇다면 왜 아벨 그룹에 관심을 갖는 걸까?트리 클릭이 이 모드를 따르기 때문에, 이것은 우리가 비슷한 일을 할 수 있음을 의미한다. (psuedo 코드)
    CPU_COUNT = 16
    TREE = '#'.freeze
    
    workers = 16.times.map do
      # This is NOT valid syntax inside the ractor, will test
      # later once I can talk to some folks
      Ractor.new do
        loop do
          # For instance this will work, but...
          Ractor.receive => { y:, slope_x:, map_line: }
    
          # This will complain about non-local references
          # even though they're local variables
          map_boundary = map_line.size - 1
          position = (y * slope_x) % map_boundary
    
          # Then this will be annoyed at `TREE` being
          # non-local despite freezing
          Ractor.yield map_line[position] == TREE ? 1 : 0
        end
      end
    end
    
    # Ractor pipe, need to figure out syntax, reading
    # through articles but rather hard to follow
    worker_queue = nil
    
    # The idea is to send lines to whatever worker, wait
    # for eventual return, and sum those all up once all
    # lines are processed.
    map.lines.map { |line| worker_queue.send(line) }.sum
    
    너는 심지어 노선을 바꿀 수도 있다. 우리가 경사도와 위치를 알기만 하면 된다.두 번째 부분은 당연히 일을 좀 복잡하게 만들 수 있지만 너무 복잡하지는 않을 것이다.
    귀신이 곡할 노릇이다. 0 이론적으로 너는 그것에 무한한 여러 개의 선을 계속 제공할 수 있다. 그것은 계속 운행할 것이다.
    여기에는 잠재력이 많지만 지금은 이해하기 어려워요. 그래서 이 잠재력을 계속 발휘해서 어떻게 이루어졌는지 알려드릴게요.
    너는 어떤 생각이나 무엇이 그것을 작용하게 하는지 아니?트위터 @keystonelemur에서 DM을 찍어 주세요. 얘기하고 싶어요.

    마감 03일
    3일의 끝과 관련하여 우리는 이 문제들을 계속 연구하고, 다음 며칠과 몇 주 내에 그들의 해결 방안과 방법을 탐색할 것이다.
    모든 원시 해결 방안을 찾으려면 the Github repo 전체 주석의 해결 방안을 보십시오.
    |

    좋은 웹페이지 즐겨찾기