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*imỗi lần, "nội tuyến" các vị trí [8,10,12,22,24,26,36,38,40].
- Các
offsetsmả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 ... endbằng {...}và chuyển đổi xung quanh in $> << foo. (Có một mẹo ở đây liên quan đến puts nilvà() == 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 injectkhô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 jkhi bắt đầu vòng lặp. (Lưu ý rằng +=8cầ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+=8thự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ả 9999vào cuối mảng khác biệt và thêm jvào cuối , không phải bắt đầu vòng lặp. Lý do là 2,2,10,2,2,10,2,2trô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 9999sẽ không thực sự ảnh hưởng đến đầu ra, vì không có a[j]cuộc gọi nào jcó 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+=8bây giờ chỉ là j=8vì nếu không chúng ta sẽ liên tục thêm 8quá nhiều. Chúng tôi cũng đã thay đổi biến khối từ jđến l.
Vì vậy, 9999phần tử không có ảnh hưởng đến đầu ra, chúng ta có thể thay đổi nó 10và 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=8trô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 8bạn có thể sử dụng để gán. Điều này cũng cần j+=lphả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_atgọ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+ injectcó 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 0trong 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_indexcó 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}