루비 (135 자)
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=[0,1,6,7,8].inject{|s,e|s+a[j+e]+a[j-e]};j+=l+2}
a.each_slice(7){|r|puts"%-3s"*7%r}
샘플 출력
2 1 6 9 4 5 1
9 34 4 37 2 31 3
7 2 3 1 8 1 7
5 42 4 40 2 47 9
3 9 9 4 9 4 7
3 44 4 41 2 47 4
6 9 1 5 7 6 8
고장
이것이 어떻게 작동하는지 너무 명확하지 않으므로 여기에 빠른 고장이 있습니다. 참고 : 아마도이 단계 중 일부를 건너 뛰고 더 짧은 버전으로 더 빨리 이동할 수는 있지만 문자를 깎은 다른 방법을 볼 수있을 정도로 교육적이라고 생각합니다. 특히 리터럴 패턴을 발견하여 2 자리 숫자를 1 자리 버전으로 바꿉니다. .
순진한 버전
2 차원 배열에 의존 하는 다른 루비 솔루션 과 달리, 1 차원 배열로 시작하여 오프셋 값으로 작업함으로써 패턴이 반복되므로 더 짧은 버전을 얻을 수 있습니다.
ary=(0..48).map { rand(9) + 1 }
offsets = [-8,-7,-6,-1,1,6,7,8]
3.times do |i|
[8,10,12].each do |j|
ary[j + 14*i] = ary.values_at(*offsets.map { |e| j+14*i + e }).inject(:+)
end
end
ary.each.with_index do |e,i|
$> << ("%-3s" % e)
$> << ?\n if i % 7==6
end
여기서 핵심 원리는 인덱스 위치 8, 10, 12에서 14의 배수로 상쇄하는 것입니다. 위치 8, 10 및 12는 요약 할 3x3 그리드의 중심입니다. 샘플 출력에서 34는 위치 8, 42는 위치 8 + 14 * 1 등 입니다. [-8,-7,-6,-1,1,6,7,8]
즉 , 위치 8에서 위치 오프셋을 기준으로 위치 8을 34로 대체 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
합니다. [8 + 14*i, 10 + 14*i, 12 + 14*i]
패턴이 반복되므로 동일한 원리가의 모든 값에 적용 됩니다.
그것을 최적화
먼저 몇 가지 빠른 최적화 :
- 매번
3.times { ... }
계산 하는 대신 j + 14*i
위치를 "인라인"합니다 [8,10,12,22,24,26,36,38,40]
.
offsets
배열 때문에 문자와 변수를 대체 한 번 사용된다.
- 교체
do ... end
로 {...}
와에 인쇄 주위 전환 $> << foo
. (여기에 포함 트릭있다 puts nil
및 () == nil
.)
- 더 짧은 변수 이름.
이 후의 코드는 177 자입니다.
a=(0..48).map{rand(9)+1}
[8,10,12,22,24,26,36,38,40].each{|j|a[j]=a.values_at(*[-8,-7,-6,-1,1,6,7,8].map{|e|j+e}).inject(:+)}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
다음 축소의 inject
경우 오프셋 배열이 순서대로 필요하지 않습니다. [-8,-7,-6,-1,1,6,7,8]
덧셈은 교환 적이므로 다른 순서 를 가질 수도 있고 다른 순서 를 가질 수도 있습니다 .
먼저 긍정과 부정을 쌍을 이루십시오 [1,-1,6,-6,7,-7,8,-8]
.
이제 짧아 질 수 있습니다
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
에
[1,6,7,8].flat_map { |e| [j+e, j-e] }
결과
a=(0..48).map{rand(9)+1}
[8,10,12,22,24,26,36,38,40].each{|j|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
어떤는 176 개 문자.
8만큼 이동하여 차이점으로 이동
두 문자 리터럴 값은 짧아 질 수있는 것처럼 보이므로 루프 시작시 업데이트 하여 [8,10,12,22,24,26,36,38,40]
모든 것을 아래로 내리십시오 . (참고 것을 피한는의 오프셋 값을 갱신 할 필요 ).8
j
+=8
1,6,7,8
a=(0..48).map{rand(9)+1}
[0,2,4,14,16,18,28,30,32].each{|j|j+=8;a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
이것은 179로, 더 크지 만 j+=8
실제로 제거 할 수 있습니다.
첫 번째 변화
[0,2,4,14,16,18,28,30,32]
차이점의 배열 :
[2,2,10,2,2,10,2,2]
이 값을 초기 값에 누적하여 추가합니다 j=8
. 이것은 결국 같은 값을 다룰 것입니다. (아마도 8만큼 먼저 이동하는 대신 이것을 바로 건너 뛸 수 있습니다.)
우리는 또한의 더미 값을 추가 할 것입니다 점에 유의 9999
차이 배열의 끝에 및 추가 j
상기 끝 이 아닌 시작 루프를. 정당화는 3 번 반복되는 동일한 3 개의 숫자에 끔찍하게2,2,10,2,2,10,2,2
보이고 , 루프 끝에서 계산 함으로써 최종 값은 실제로 출력에 영향을 미치지 않습니다. 어떤 가치가 있는 호출 이 없기 때문입니다 이상 .j+difference
9999
a[j]
j
10000
a=(0..48).map{rand(9)+1}
j=8
[2,2,10,2,2,10,2,2,9999].each{|l|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+);j+=l}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
이 차이점 배열을 사용하면 물론 j+=8
이제는 그냥 그렇습니다. j=8
그렇지 않으면 반복적으로 8
너무 많이 추가하기 때문입니다. 또한 블록 변수를에서 j
로 변경 했습니다 l
.
따라서 9999
요소는 출력에 영향을 미치지 않기 때문에 요소를 변경 10
하고 배열을 줄일 수 있습니다 .
a=(0..48).map{rand(9)+1}
j=8
([2,2,10]*3).each{|l|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+);j+=l}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
이다 170 개 문자.
그러나 이제는 j=8
외형이 약간 어수선 해져 2 개씩 [2,2,10]
아래로 이동 하여 2 개 문자를 절약 하여 편리하게 8
할당 할 수 있습니다. 이것 또한 j+=l
되어야 j+=l+2
합니다.
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+);j+=l+2}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
이다 169 개 문자. 7자를 짜는 둥근 길이지만 깔끔합니다.
최종 조정
values_at
호출은 실제로 일종의 중복이다, 우리는 인라인 수있는 Array#[]
전화를. 그래서
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
된다
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
또한 배열 의 이니셜 을 사용하여 flat_map
+ j+e/j-e
+ inject
를 더 직접적인 합계로 줄일 수 있음을 알 수 있습니다 0
.
이렇게하면 152자가 됩니다.
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=[0,1,6,7,8].inject{|s,e|s+a[j+e]+a[j-e]};j+=l+2}
a.map.with_index{|e,i|$><<"%-3s"%e<<(?\nif i%7==6)}
드디어:
map.with_index
될 수 있습니다 each_slice
.
- 인쇄 방식을 변경하십시오.
135 :
a=(0..48).map{rand(9)+1}
([0,0,j=8]*3).each{|l|a[j]=[0,1,6,7,8].inject{|s,e|s+a[j+e]+a[j-e]};j+=l+2}
a.each_slice(7){|r|puts"%-3s"*7%r}