Ruby (135 ký tự)
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}
Sản lượng mẫu
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
Phá vỡ
Nó không quá rõ ràng làm thế nào điều này hoạt động, vì vậy đây là một sự cố nhanh chóng. GHI CHÚ: Bạn có thể có thể bỏ qua một số bước này và chuyển sang các phiên bản ngắn hơn nhanh hơn, nhưng tôi nghĩ rằng nó đủ giáo dục để xem các cách khác nhau để tôi loại bỏ các ký tự, đặc biệt là bằng cách phát hiện các mẫu trong chữ để biến các số có 2 chữ số thành phiên bản 1 chữ số .
Phiên bản ngây thơ
Không giống như các giải pháp Ruby khác dựa trên mảng hai chiều, cuối cùng, bạn có thể có được phiên bản ngắn hơn bằng cách bắt đầu với mảng 1 chiều và làm việc với các giá trị offset, do các mẫu lặp lại.
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
Nguyên tắc chính ở đây là chúng tôi làm việc tại các vị trí chỉ số 8, 10, 12, chỉ cần bù cho bội số của 14. Vị trí 8, 10 và 12 là trung tâm của các lưới 3x3 mà chúng tôi đang tổng hợp. Trong đầu ra mẫu, 34 là vị trí 8, 42 là vị trí 8 + 14 * 1, v.v. Chúng tôi thay thế vị trí 8 bằng 34 bằng vị trí bù từ vị trí 8 bằng [-8,-7,-6,-1,1,6,7,8]
- nói cách khác 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8])
. Nguyên tắc tương tự này đúng với tất cả các giá trị của [8 + 14*i, 10 + 14*i, 12 + 14*i]
, vì mẫu lặp lại.
Tối ưu hóa nó
Đầu tiên, một số tối ưu hóa nhanh chóng:
- Thay vì
3.times { ... }
và tính toán j + 14*i
mỗi lần, "nội tuyến" các vị trí [8,10,12,22,24,26,36,38,40]
.
- Các
offsets
mảng được sử dụng một lần, vì vậy thay thế các biến với các chữ.
- Thay thế
do ... end
bằng {...}
và chuyển đổi xung quanh in $> << foo
. (Có một mẹo ở đây liên quan đến puts nil
và() == nil
.)
- Tên biến ngắn hơn.
Mã sau này là 177 ký tự:
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)}
Đối với lần giảm tiếp theo, lưu ý rằng inject
không cần mảng bù theo thứ tự. Chúng tôi có thể có [-8,-7,-6,-1,1,6,7,8]
hoặc một số thứ tự khác, vì bổ sung là giao hoán.
Vì vậy, trước tiên hãy kết hợp các mặt tích cực và tiêu cực để có được [1,-1,6,-6,7,-7,8,-8]
.
Bây giờ bạn có thể rút ngắn
[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)
đến
[1,6,7,8].flat_map { |e| [j+e, j-e] }
Kết quả này trong
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)}
đó là 176 ký tự.
Thay đổi 8 và di chuyển đến sự khác biệt
Các giá trị theo nghĩa đen gồm hai ký tự có vẻ như chúng có thể được rút ngắn, vì vậy hãy lấy [8,10,12,22,24,26,36,38,40]
và dịch chuyển mọi thứ xuống 8
, cập nhật j
khi bắt đầu vòng lặp. (Lưu ý rằng +=8
cần tránh cập nhật các giá trị bù của 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)}
Đây là 179, lớn hơn, nhưng j+=8
thực sự có thể được gỡ bỏ.
Thay đổi đầu tiên
[0,2,4,14,16,18,28,30,32]
đến một loạt các khác biệt:
[2,2,10,2,2,10,2,2]
và tích lũy thêm các giá trị này vào ban đầu j=8
. Điều này cuối cùng sẽ bao gồm các giá trị tương tự. (Có lẽ chúng ta có thể bỏ qua điều này thay vì thay đổi 8 lần đầu tiên.)
Lưu ý rằng chúng tôi cũng sẽ thêm một giá trị giả 9999
vào cuối mảng khác biệt và thêm j
vào cuối , không phải bắt đầu vòng lặp. Lý do là 2,2,10,2,2,10,2,2
trông rất giống với 3 số giống nhau được lặp lại 3 lần và bằng cách tính toán j+difference
ở cuối vòng lặp, giá trị cuối cùng 9999
sẽ không thực sự ảnh hưởng đến đầu ra, vì không có a[j]
cuộc gọi nào j
có giá trị trên 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)}
Với mảng khác biệt này , tất nhiên j+=8
bây giờ chỉ là j=8
vì nếu không chúng ta sẽ liên tục thêm 8
quá nhiều. Chúng tôi cũng đã thay đổi biến khối từ j
đến l
.
Vì vậy, 9999
phần tử không có ảnh hưởng đến đầu ra, chúng ta có thể thay đổi nó 10
và rút ngắn mảng.
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)}
Đây là 170 ký tự.
Nhưng bây giờ j=8
trông có vẻ hơi lộn xộn, và bạn có thể lưu 2 ký tự bằng cách chuyển [2,2,10]
xuống 2 để thuận tiện lấy một cái 8
bạn có thể sử dụng để gán. Điều này cũng cần j+=l
phải trở thành 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)}
Đây là 169 ký tự. Một cách xoay quanh để ép 7 ký tự, nhưng nó gọn gàng.
Tinh chỉnh cuối cùng
Cuộc values_at
gọi này thực sự là dư thừa và chúng ta có thể thực hiện Array#[]
cuộc gọi. Vì thế
a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)
trở thành
[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)
Bạn cũng có thể nhận ra rằng flat_map
+ j+e/j-e
+ inject
có thể được giảm xuống thành một tổng kết trực tiếp hơn với một chữ cái đầu tiên 0
trong mảng.
Điều này để lại cho bạn 152 ký tự:
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)}
Cuối cùng:
map.with_index
có thể trở thành each_slice
.
- Thay đổi cách tiếp cận in ấn.
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}