17
\$\begingroup\$

Generate a 7 by 7 grid, filled with random numbers. However, in cells with an odd row and column number (starting at 0), you must use the sum of the surrounding cells. Here's a small example with a 3 by 3 grid (sum-square bolded):

2 2  2
2 16 2
2 2  2

And here's an example 7 by 7 grid:

6 5  4 3  7 2  5
6 43 3 50 8 43 8
4 7  8 8  9 3  1
4 36 1 43 6 40 5
3 3  6 1  4 7  5
4 35 3 45 9 42 1
2 6  8 6  8 5  3

Rules

  • Numbers that are not sums must always be between 1 and 9 inclusive.

  • Grid must be randomly generated. For each non-sum, every digit must have an equal chance of appearing, regardless of which cell it is in.

  • Numbers must be aligned. This means that either the first or last digit of each number in a column must line up vertically. (You may assume that the middle numbers will always be two digits.)

  • Surrounding cells includes diagonals. Therefore, each sum square will have eight numbers surrounding it, which you must add.

  • Shortest code wins, since this is .

\$\endgroup\$
3
  • 3
    \$\begingroup\$ Does it have to be the first digit that lines up? i.e. can it be the last? \$\endgroup\$
    – Volatility
    Commented Aug 31, 2013 at 6:28
  • \$\begingroup\$ @Volatility I suppose right align would work. edited \$\endgroup\$
    – Doorknob
    Commented Aug 31, 2013 at 13:14
  • \$\begingroup\$ What if a language doesn't have a random number generator? \$\endgroup\$
    – Heimdall
    Commented Nov 2, 2017 at 11:24

20 Answers 20

15
\$\begingroup\$

APL, 53 49 43 42 40 39 36

I managed to replicate J's ;. in APL, and used Gareth's approach, saving 13 chars.

{×5⌷⍵:5⌷⍵⋄+/⍵}¨3,⌿3,/×∘?∘9¨∘.∨⍨9⍴0 1

Sample run:

      {×5⌷⍵:5⌷⍵⋄+/⍵}¨3,⌿3,/×∘?∘9¨∘.∨⍨9⍴0 1
9  9 6  1 7  5 6
7 55 5 39 9 54 9
9  8 2  1 8  1 9
2 43 8 41 6 42 5
7  3 4  4 8  3 2
2 29 1 26 2 35 8
6  4 2  3 2  3 7

Explanation:

  • ∘.∨⍨9⍴0 1 generates a bit mask.
  • ×∘?∘9¨ multiplies each bit by a random value from 1 to 9 inclusive, generating a masked grid of random numbers.
  • 3,⌿3,/ uses what can only be described as hackery to return all 3 by 3 overlapping boxes in the masked array. These are also flattened in the process.
  • {×5⌷⍵:5⌷⍵⋄+/⍵}¨ iterates over the array, assigning each element to . For each iteration, it takes the fifth (middle, remembering that APL indexing is 1-based), and returns its sign. In this case this is equivalent to testing if the number is greater than 0. If this returns 1 (for true), then return that element. Otherwise, return the sum of the elements in the flattened 3 by 3 box. It uses the :⋄ ternary operator, which is the equivalent of ?: in many languages.
\$\endgroup\$
3
  • \$\begingroup\$ Uh-oh. Looks like I'm going to have to find more character savings. :-S \$\endgroup\$
    – Gareth
    Commented Sep 3, 2013 at 10:31
  • \$\begingroup\$ @Gareth well, look what we have here. I'm back in the lead :P \$\endgroup\$
    – Volatility
    Commented Sep 3, 2013 at 10:41
  • \$\begingroup\$ NOOOOOOOOOO!!!!!!! :-( \$\endgroup\$
    – Gareth
    Commented Sep 3, 2013 at 11:53
12
\$\begingroup\$

J, 63 61 59 55 52 51 49 47 39 37 characters

3 3(4&{+4{*|+/)@,;._3(**1+?)+./~9$0 9

With thanks to Volatility for his 10 character saving.

Explanation (each step will have different random numbers...):

Generate the mask for generating the random numbers (uses $:

   9 9$9$0 9
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0
0 9 0 9 0 9 0 9 0

Now we have a hook. This is actually a happy accident from when I was whittling down an earlier version. It was meant to be transpose |: and OR +. with the original. It made sense since I was using ones and zeroes at the time, but now I have nines and zeroes. It just so happens that it works in the same way with the GCD meaning of +.. Lucky for me. :-)

   (+.|:)9 9$9$0 9
0 9 0 9 0 9 0 9 0
9 9 9 9 9 9 9 9 9
0 9 0 9 0 9 0 9 0
9 9 9 9 9 9 9 9 9
0 9 0 9 0 9 0 9 0
9 9 9 9 9 9 9 9 9
0 9 0 9 0 9 0 9 0
9 9 9 9 9 9 9 9 9
0 9 0 9 0 9 0 9 0

So, now that we have a grid of 9s and 0s we want to generate some random numbers. ? generates a random number from 0 up to (but not including) a given number. Given a list it will generate one random number in this way for each member of the list. So in this case it will generate a number from 0 to 8 for every 9 in the table and a floating point number from 0 to 1 for each 0.

   ?(+.|:)9 9$9$0 9
 0.832573 7 0.926379 7 0.775468 6 0.535925 3  0.828123
        7 0        5 5        4 3        4 5         4
0.0944584 2 0.840913 2 0.990768 1 0.853054 3  0.881741
        3 8        7 0        8 3        3 4         8
 0.641563 4 0.699892 7 0.498026 1 0.438401 6  0.417791
        6 8        7 5        2 3        6 6         3
 0.753671 6 0.487016 4 0.886369 7 0.489956 5  0.902991
        3 4        7 8        1 4        8 0         8
0.0833539 4 0.311055 4 0.200411 6 0.247177 5 0.0464731

But we want numbers from 1 to 9 not 0 to 8. So we add 1.

   (1+?)(+.|:)9 9$9$0 9
 1.4139 4  1.7547 7 1.67065 4 1.52987 1 1.96275
      2 8       2 4       3 9       6 9       9
1.15202 7 1.11341 5  1.0836 1 1.24713 2 1.13858
      9 3       3 2       4 7       3 8       6
1.06383 9 1.67909 4 1.09801 8  1.4805 6  1.0171
      9 5       5 5       9 5       9 4       3
1.22819 1 1.85259 4 1.95632 6 1.33034 3 1.39417
      4 2       5 1       3 7       2 5       6
1.06572 5  1.9942 5 1.78341 5 1.16516 6 1.37087

This is very nice but we've lost the zeroes that I want, so we'll multiply it by the original mask after turning all the nines into ones. I do this by checking if the value is greater than 1. That gives us: (1&<*1+?).
There are a couple of things going on here:

  • We've created a fork which allows us to pack a lot of work into very few characters.
  • We've bonded (&) the 1 to the < verb.

So all combined the (1&<*1+?) is generating random numbers, and zeroing all the numbers which where generated by zeroes in the original grid.

   (1&<*1+?)(+.|:)9 9$9$0 9
0 3 0 2 0 7 0 1 0
9 5 2 7 7 1 4 5 7
0 6 0 8 0 3 0 1 0
4 8 7 5 9 7 7 9 4
0 9 0 6 0 9 0 9 0
6 1 2 1 4 6 8 9 4
0 3 0 8 0 6 0 6 0
2 5 2 2 2 2 3 9 3
0 9 0 3 0 5 0 3 0

The next bit is the (in my opinion, anyway :-) clever bit.
The cut ;. verb has a form x u;._3 y which cuts the input into boxes described by x, and then applies the verb u to them. In this case we have 3 3(4&{++/*0=4&{)@,;._3.

  • The 3 3 is describing the boxes we want - 3x3.
  • The (4&{++/*0=4&{)@, is a verb train which describes what we want to do to each box.

To demonstrate the ;. verb I'll use < to show each box:

   3 3(<);._3(1&<*1+?)(+.|:)9 9$9$0 9
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│0 8 0│8 0 7│0 7 0│7 0 4│0 4 0│4 0 3│0 3 0│
│9 1 3│1 3 2│3 2 3│2 3 8│3 8 5│8 5 5│5 5 9│
│0 6 0│6 0 1│0 1 0│1 0 2│0 2 0│2 0 4│0 4 0│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│9 1 3│1 3 2│3 2 3│2 3 8│3 8 5│8 5 5│5 5 9│
│0 6 0│6 0 1│0 1 0│1 0 2│0 2 0│2 0 4│0 4 0│
│7 1 6│1 6 7│6 7 1│7 1 2│1 2 1│2 1 6│1 6 1│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│0 6 0│6 0 1│0 1 0│1 0 2│0 2 0│2 0 4│0 4 0│
│7 1 6│1 6 7│6 7 1│7 1 2│1 2 1│2 1 6│1 6 1│
│0 7 0│7 0 5│0 5 0│5 0 9│0 9 0│9 0 7│0 7 0│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│7 1 6│1 6 7│6 7 1│7 1 2│1 2 1│2 1 6│1 6 1│
│0 7 0│7 0 5│0 5 0│5 0 9│0 9 0│9 0 7│0 7 0│
│7 9 9│9 9 7│9 7 1│7 1 9│1 9 4│9 4 9│4 9 5│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│0 7 0│7 0 5│0 5 0│5 0 9│0 9 0│9 0 7│0 7 0│
│7 9 9│9 9 7│9 7 1│7 1 9│1 9 4│9 4 9│4 9 5│
│0 3 0│3 0 2│0 2 0│2 0 7│0 7 0│7 0 9│0 9 0│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│7 9 9│9 9 7│9 7 1│7 1 9│1 9 4│9 4 9│4 9 5│
│0 3 0│3 0 2│0 2 0│2 0 7│0 7 0│7 0 9│0 9 0│
│3 1 6│1 6 1│6 1 7│1 7 6│7 6 8│6 8 9│8 9 9│
├─────┼─────┼─────┼─────┼─────┼─────┼─────┤
│0 3 0│3 0 2│0 2 0│2 0 7│0 7 0│7 0 9│0 9 0│
│3 1 6│1 6 1│6 1 7│1 7 6│7 6 8│6 8 9│8 9 9│
│0 9 0│9 0 3│0 3 0│3 0 4│0 4 0│4 0 3│0 3 0│
└─────┴─────┴─────┴─────┴─────┴─────┴─────┘

Some things to notice:

  • The boxes overlap - the second and third columns in the top left box are the first and second in the box to the right of it.
  • There are 7x7 boxes. That's why we had a 9x9 grid initially.
  • Each place we require a sum has a 0 at the box's centre.

Now we just need to either pass the value at the centre back (if it's non-zero) or sum the numbers in the 3x3 box (if the centre is zero).
To do this we need easy access to the centre number. , helps here. It turns the 3x3 grid into a list of 9 items with the centre number at number 4.
4&{ will use { to pull out the centre value and then compare it with 0: 0=4&{. This returns a 0 or 1 for true or false, which we then multiply by the sum +/. If it was zero at the centre we now have our sum as required. If it was not we have zero, so to finish off we just add the centre value 4&{+.
This gives the verb train (4&{++/*0=4&{)@,

   3 3(4&{++/*0=4&{)@,;._3(1&<*1+?)(+.|:)9 9$9$0 9
2  6 9  3 7  9 7
3 47 6 51 5 49 5
3  9 9  6 6  2 8
7 48 6 47 1 37 5
5  4 5  7 7  2 6
5 35 3 49 8 51 9
1  6 6  6 7  4 8
\$\endgroup\$
10
  • \$\begingroup\$ Does your one line of code do all that, including generate the random numbers? Reassure me. Just finding it hard to believe. \$\endgroup\$
    – DavidC
    Commented Sep 1, 2013 at 19:56
  • \$\begingroup\$ Yep, hard as it may be to believe. The random bit is done by the ?. I'll change the explanation to reflect the newest version. \$\endgroup\$
    – Gareth
    Commented Sep 1, 2013 at 19:59
  • \$\begingroup\$ @DavidCarraher Most verbs in J are either 1 or 2 characters so 47 characters can pack in a lot of work. \$\endgroup\$
    – Gareth
    Commented Sep 1, 2013 at 20:02
  • \$\begingroup\$ The cutting of a 9x9 box into 7x7 overlapping squares is definitely the clever bit. In less than 10 minutes I've been able to apply it to beat my current GolfScript implementation by 7.5%. \$\endgroup\$ Commented Sep 1, 2013 at 20:57
  • \$\begingroup\$ Oh well, looks like it's back to the drawing board for me. \$\endgroup\$
    – Volatility
    Commented Sep 1, 2013 at 21:20
5
\$\begingroup\$

Ruby (135 characters)

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}

Sample output

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  

Breakdown

It's not too obvious how this works, so here's a quick breakdown. NOTE: You can probably skip some of these steps and jump to shorter versions more quickly, but I think it's educational enough to see different ways I shaved off characters, especially by spotting patterns in literals to turn 2-digit numbers into 1-digit versions.

Naive version

Unlike the other Ruby solutions that rely on a two-dimensional array, you can (eventually) get a shorter version by starting with a 1-dimensional array and working with offset values, since the patterns repeat.

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

The key principle here is that we're working at index positions 8, 10, 12, just offset by multiples of 14. Positions 8, 10 and 12 are the centers of the 3x3 grids that we're summing up. In the sample output, 34 is position 8, 42 is position 8 + 14*1, etc. We replace position 8 with 34 by positions offset from position 8 by [-8,-7,-6,-1,1,6,7,8] — in other words 34 = sum(ary[8-8], ary[8-7], ..., ary[8+8]). This same principle holds for all the values of [8 + 14*i, 10 + 14*i, 12 + 14*i], since the pattern repeats.

Optimising it

First, some quick optimisations:

  • Instead of 3.times { ... }, and calculating j + 14*i each time, "inline" the positions [8,10,12,22,24,26,36,38,40].
  • The offsets array is used once, so replace the variable with the literal.
  • Replace do ... end with {...} and switch around the printing to $> << foo. (There's a trick here involving puts nil and () == nil.)
  • Shorter variable names.

The code after this is 177 characters:

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)}

For the next reduction, note that the inject doesn't need the offsets array to be in order. We can either have [-8,-7,-6,-1,1,6,7,8] or some other ordering, since addition is commutative.

So first pair up the positives and the negatives to get [1,-1,6,-6,7,-7,8,-8].

Now you can shorten

[1,-1,6,-6,7,-7,8,-8].map { |e| j+e }.inject(:+)

to

[1,6,7,8].flat_map { |e| [j+e, j-e] }

This results in

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)}

which is 176 characters.

Shift by 8 and move to differences

The two-character literal values seem like they can be shortened away, so take [8,10,12,22,24,26,36,38,40] and shift everything down by 8, updating j at the start of the loop. (Note that +=8 avoids needing to update the offset values of 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)}

This is 179, which is bigger, but the j+=8 can actually be removed.

First change

[0,2,4,14,16,18,28,30,32]

to an array of differences:

[2,2,10,2,2,10,2,2]

and cumulatively add these values to an initial j=8. This will eventually cover the same values. (We could probably skip straight to this instead of shifting by 8 first.)

Note that we'll also add a dummy value of 9999 to the end of the differences array, and add to j at the end, not the start of the loop. The justification is that 2,2,10,2,2,10,2,2 looks awfully close to being the same 3 numbers repeated 3 times, and by computing j+difference at the end of the loop, the final value of 9999 won't actually affect the output, since there isn't a a[j] call where j is some value over 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)}

With this differences array, the j+=8 is now just j=8, of course, since otherwise we'd repeatedly add 8 too many. We've also changed the block variable from j to l.

So since the 9999 element has no effect on the output, we can change it to 10 and shorten the array.

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)}

This is 170 characters.

But now the j=8 looks a bit clunky, and you can save 2 characters by shifting [2,2,10] down by 2 to conveniently get an 8 you can use for assignment. This also needs j+=l to become 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)}

This is 169 characters. A round-about way to squeeze 7 characters, but it's neat.

Final tweaks

The values_at call is actually sort of redundant, and we can inline an Array#[] call. So

a.values_at(*[1,6,7,8].flat_map{|e|[j+e,j-e]}).inject(:+)

becomes

[1,6,7,8].flat_map{|e|[a[j+e],a[j-e]]}.inject(:+)

You can also spot that flat_map + j+e/j-e + inject can be reduced to a more direct summation with an initial 0 in the array.

This leaves you with 152 characters:

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)}

Finally:

  • map.with_index can become each_slice.
  • Change the printing approach.

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}
\$\endgroup\$
1
  • \$\begingroup\$ You can replace each with map for one byte. \$\endgroup\$
    – Jordan
    Commented Nov 1, 2017 at 19:27
3
\$\begingroup\$

Python, 132

This doesn't technically satisfy the rules, because the last digits of each number are aligned rather than the first. But I thought I'd share anyway:

import numpy
G=numpy.random.randint(1,10,(7,7))
G[1::2,1::2]=sum(G[i:6+i:2,j:6+j:2]for i in[0,1,2]for j in[0,1,2]if i&j!=1)
print G

Sample output:

[[ 8  9  8  3  8  5  8]
 [ 6 53  4 45  8 53  8]
 [ 8  2  8  1  5  3  8]
 [ 2 40  6 34  1 32  7]
 [ 4  1  9  1  3  3  2]
 [ 4 35  7 35  6 31  1]
 [ 1  7  2  5  2  8  6]]
\$\endgroup\$
3
\$\begingroup\$

Mathematica, 108

s=#-1;;#+1&;g=1+8~RandomInteger~{7,7};Column/@
ReplacePart[g,{i_?EvenQ,j_?EvenQ}:>g〚s@i,s@j〛~Total~2-g〚i,j〛]

result

For prettier output Column/@ can be replaced with TableForm@ at a cost of 2 characters.

\$\endgroup\$
5
  • \$\begingroup\$ Very, very clever.Grid[ReplacePart[ g, {i_?EvenQ, j_?EvenQ} :> g[[s@i, s@j]]~Total~2 - g[[i, j]]]\[Transpose]] gives a cleaner output and saves a couple of characters iff you count Transpose as a single character, which it is in Mathmatica. Btw, Wolfram's OneLinerSubmission template counted 106 characters, 105 with the one character Transpose. \$\endgroup\$
    – DavidC
    Commented Sep 1, 2013 at 20:15
  • \$\begingroup\$ @DavidCarraher Thanks. The char count is due to unnecessary newline and :> being one symbol, although it's in the private use area of unicode. One could even remove the transpose, since the validity summation rule holds even after transposition. But it seems Grid doesn't align the entries without further options (v8) \$\endgroup\$
    – ssch
    Commented Sep 1, 2013 at 23:45
  • \$\begingroup\$ Grid centers the numbers within columns. Technically, that would not satisfy the challenge, but it does look better than having a list appear in the displayed table. \$\endgroup\$
    – DavidC
    Commented Sep 2, 2013 at 1:34
  • \$\begingroup\$ Very nice. I just spend considerable time creating the same thing, only I used Part and Tuples. Posting soon. \$\endgroup\$
    – Mr.Wizard
    Commented Sep 3, 2013 at 11:34
  • \$\begingroup\$ You could save two characters with this: p=2|4|6;Column/@ReplacePart[g,{i:p,j:p}:>g[[s@i,s@j]]~Total~2-g[[i,j]]] \$\endgroup\$
    – Mr.Wizard
    Commented Sep 3, 2013 at 11:49
3
\$\begingroup\$

GolfScript (79 78 72 70 68 66 65 60 chars)

56,{13%5<,~9rand)}%9/`{>3<zip`{>3<(*(+(\{+}*or' '}+7,%n}+7,/

NB This contains a literal tab, which Markdown may well break.

The clever bit is due to Gareth: see his J solution.

Online demo

\$\endgroup\$
3
\$\begingroup\$

R: 114 characters

a=array(sample(1:9,49,r=T),c(7,7))
for(i in 2*1:3){for(j in 2*1:3)a[i,j]=sum(a[(i-1):(i+1),(j-1):(j+1)])-a[i,j]}
a

First line create a 7 by 7 array filled with randomly chosen numbers from 1 to 9 (uniform distribution with replacement, hence r=T which stands for replace=TRUE). Second line, compute sums of 3 by 3 grids, substract center and replace it with the result. Third line print the resulting grid (by default, matrix and array columns are right aligned).

Example output:

     [,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,]    8    5    6    4    3    2    2
[2,]    1   37    6   41    7   38    8
[3,]    5    3    3    3    9    4    3
[4,]    4   31    3   41    3   44    9
[5,]    3    5    5    9    6    7    3
[6,]    3   32    2   40    4   37    5
[7,]    8    2    4    1    9    1    2
\$\endgroup\$
2
\$\begingroup\$

J, 67 65 bytes

A naïve and verbose solution in J. It is a straightforward implementation of the task.

(+/^:_"2((,&.>/@(<:,],>:)"0)&.>m){0 m}a)(m=.{;~1 3 5)}a=.>:?7 7$9

First I create a 7 x 7 array of integers between 1 and 9. In fact J's ? verb generates numbers up to its argument, that's why we need to increment each element, >: in J

a=.>:?7 7$9 
2 8 7 4 4 5 1
4 5 4 1 6 7 9
3 8 3 6 5 3 3
6 8 6 3 7 7 1
7 7 4 4 5 9 9
2 3 6 5 2 2 9
2 2 6 8 8 1 3

I prepare a mask to be used for zeroing of the odd row/col cells, a pairs of odd row/column indices:

m=.{;~1 3 5
┌───┬───┬───┐
│1 1│1 3│1 5│
├───┼───┼───┤
│3 1│3 3│3 5│
├───┼───┼───┤
│5 1│5 3│5 5│
└───┴───┴───┘

The Catalogue verb { combines items from the atoms inside the boxed list

┌─────┬─────┐
│1 3 5│1 3 5│
└─────┴─────┘

to form a catalogue, the 3x3 table of the pairs above

Then I prepare a table of row/col indices to be used for selection of each of the 3x3 subarrays.

s=.(,&.>/@(<:,],>:)"0)&.>m
┌─────────────┬─────────────┬─────────────┐
│┌─────┬─────┐│┌─────┬─────┐│┌─────┬─────┐│
││0 1 2│0 1 2│││0 1 2│2 3 4│││0 1 2│4 5 6││
│└─────┴─────┘│└─────┴─────┘│└─────┴─────┘│
├─────────────┼─────────────┼─────────────┤
│┌─────┬─────┐│┌─────┬─────┐│┌─────┬─────┐│
││2 3 4│0 1 2│││2 3 4│2 3 4│││2 3 4│4 5 6││
│└─────┴─────┘│└─────┴─────┘│└─────┴─────┘│
├─────────────┼─────────────┼─────────────┤
│┌─────┬─────┐│┌─────┬─────┐│┌─────┬─────┐│
││4 5 6│0 1 2│││4 5 6│2 3 4│││4 5 6│4 5 6││
│└─────┴─────┘│└─────┴─────┘│└─────┴─────┘│
└─────────────┴─────────────┴─────────────┘

For each pair in the m array I make a pair of triplets, centered around each number of the m pair:

        ┌─────┬─────┐
 1 3 -> │0 1 2│2 3 4│
        └─────┴─────┘

These pairs of triplets are used by the J From verb {, which can select multiple rows and columns simultaneously. 0 1 2 / 2 3 4 means that I select rows 0, 1 and 2 together with columns 2, 3 and 4, thus selecting the second 3x3 subarray on the top.

Finally, I can use the 7x7 array and the masks to achieve the task: First I use m as a mask to set the corresponding elements to 0:

0 m}a

Then I take all the 3x3 subarrays using s as a selector and find their sums:

+/^:_"2 s{0 m}a

Then I put these numbers back into the starting array.

 (+/^:_"2 s{0 m}a)m}a 
2  8 7  4 4  5 1
4 39 4 39 6 36 9
3  8 3  6 5  3 3
6 44 6 40 7 42 1
7  7 4  4 5  9 9
2 36 6 43 2 46 9
2  2 6  8 8  1 3

Try it online!

\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog Unicode), 32 31 30 bytesSBCS

-1 byte thanks to @jslip

|a-m×+/+/⊢⌺3 3⊢a←?9⌈m←∘.⍱⍨2|⍳7

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ ∧/¨~ -> ⍱/¨ \$\endgroup\$
    – jslip
    Commented Aug 12, 2018 at 1:28
  • \$\begingroup\$ @jslip Ah, de Morgan's laws. Thanks :) \$\endgroup\$
    – ngn
    Commented Aug 12, 2018 at 7:21
1
\$\begingroup\$

Ruby, 207

I shall present my solution first (as I always do):

a=Array.new(7){Array.new(7){rand(9)+1}}
s=[-1,0,1]
s=s.product s
s.slice!4
r=[1,3,5]
r.product(r).map{|x|u=0
s.map{|y|u+=a[x[0]+y[0]][x[1]+y[1]]}
a[x[0]][x[1]]=u}
puts a.map{|x|x.map{|y|y.to_s.ljust 3}.join
\$\endgroup\$
1
\$\begingroup\$

Ruby, 150 characters

v=(a=0..6).map{a.map{rand(9)+1}}
(o=[1,3,5]).map{|i|o.map{|j|v[i][j]=0
(d=[0,-1,1]).map{|r|d.map{|c|v[i][j]+=v[i+r][j+c]}}}}
puts v.map{|r|"%-3d"*7%r}

if the left justification requirement justification is just that ljust would have to be used... well, no. I love Ruby's formatting capabilities.

Do not use Array.new(7){...}. (0..6).map{...} is both shorter and more readable and you get an assignable range for free.

Line #3 inspired by Doorknob's solution.

\$\endgroup\$
1
\$\begingroup\$

GolfScript, 87 chars

49,{.1&\7/1&!|9rand)*}%.7/{[..1>@0\+]zip{{+}*}%);}:^%zip{^~}%]zip{.0=!=}%{'  '+3<}%7/n*

There are too many zips in there... (see online)

3  9  9  3  3  9  8  
6  46 2  50 3  39 8  
7  3  7  2  4  7  3  
8  33 9  51 8  49 5  
4  3  9  9  3  9  2  
1  45 9  41 6  33 2  
4  3  6  1  6  1  4  
\$\endgroup\$
1
\$\begingroup\$

J, 58/64/67 characters

0j_1":(7$0,:7$0 1){"0 1 |:>v;v-~7 7{.0,.0,3+/\"1]3+/\v=.1+?7 7$9

While the specification requires the numbers to be left-aligned, there is no requirement to use the decimal notation, so I guess this is valid output:

1.0e0 8.0e0 9.0e0 6.0e0 2.0e0 9.0e0 6.0e0
6.0e0 3.9e1 8.0e0 4.0e1 2.0e0 3.8e1 4.0e0
1.0e0 4.0e0 2.0e0 8.0e0 3.0e0 9.0e0 3.0e0
2.0e0 2.4e1 5.0e0 4.1e1 9.0e0 4.7e1 8.0e0
1.0e0 3.0e0 6.0e0 5.0e0 3.0e0 5.0e0 7.0e0
4.0e0 3.0e1 1.0e0 2.3e1 1.0e0 3.1e1 1.0e0
6.0e0 5.0e0 4.0e0 2.0e0 1.0e0 5.0e0 8.0e0

If right alignment instead of left alignmnent is acceptable, we're at 58 characters

(7$0,:7$0 1){"0 1 |:>v;v-~7 7{.0,.0,3+/\"1]3+/\v=.1+?7 7$9

J's ": (format) has three formatting modes:

  • right-aligned with n digits or with shrink-wrap (default display)
  • left-aligned scientific notation with n digits and m characters total
  • shrinkwrap boxed display with (left/center/right)-(top/middle/bottom) alignment (below, 69 characters)

The most verbose but also most versatile and the only one able to produce the output as per the example is the 8!:2 formatting foreign, which takes a formatting string as its left argument. Also 67 characters:

'l3.'8!:2(7$0,:7$0 1){"0 1 |:>v;v-~7 7{.0,.0,3+/\"1]3+/\v=.1+?7 7$9

Here is the boxed format:

 0 0":<"0(7$0,:7$0 1){"0 1 |:>v;v-~7 7{.0,.0,3+/\"1]3+/\v=.1+?7 7$9
 
 ┌─┬──┬─┬──┬─┬──┬─┐
 │2│6 │5│7 │5│7 │6│
 ├─┼──┼─┼──┼─┼──┼─┤
 │8│40│4│35│9│49│6│
 ├─┼──┼─┼──┼─┼──┼─┤ 
 │6│7 │2│2 │1│9 │6│
 ├─┼──┼─┼──┼─┼──┼─┤
 │8│41│9│35│3│45│7│
 ├─┼──┼─┼──┼─┼──┼─┤
 │3│1 │5│6 │7│8 │4│
 ├─┼──┼─┼──┼─┼──┼─┤
 │7│37│4│45│6│48│8│
 ├─┼──┼─┼──┼─┼──┼─┤
 │8│4 │5│4 │8│1 │6│
 └─┴──┴─┴──┴─┴──┴─┘
\$\endgroup\$
1
\$\begingroup\$

Perl, 117 characters

print$_,++$j%7?$":$/for map{++$i/7&$i%7&1?
eval join"+",@x[map{$i+$_,$i-$_}1,6,7,8]:" $_"}@x=map{1+int rand 9}$i--..48

This is one of those Perl scripts where all but one of the for loops have been collapsed into map calls so that everything can be done in a single statement. Global variables also make some important appearances in this one. I guess what I'm trying to say here is, this program is a bit gross.

Wait, it gets worse: There's a known bug in the script! It has less than a one-in-a-million chance of getting triggered, though, so I haven't gotten around to fixing it yet.

\$\endgroup\$
2
  • \$\begingroup\$ Don't hold out on us, what is the bug? \$\endgroup\$
    – user8777
    Commented Sep 1, 2013 at 1:45
  • \$\begingroup\$ Bonus points to the first person who spots it! \$\endgroup\$
    – breadbox
    Commented Sep 1, 2013 at 2:23
1
\$\begingroup\$

Mathematica, 106 / 100

I came up with something very similar to ssch's code, before seeing it. I am borrowing his idea of using Column. With ASCII only, 106:

s=#-1;;#+1&
a=8~RandomInteger~{7,7}+1
a[[##]]=a[[s@#,s@#2]]~Total~2-a[[##]];&@@@{2,4,6}~Tuples~2
Column/@a

With Unicode characters (as used by ssch), 100:

s=#-1;;#+1&
a=8~RandomInteger~{7,7}+1
a〚##〛=a〚s@#,s@#2〛~Total~2-a〚##〛;&@@@{2,4,6}~Tuples~2
Column/@a
\$\endgroup\$
1
\$\begingroup\$

Excel VBA, 74 bytes

VBE immediate function that outputs to [B2:H9].

[B2:H9]="=IF(ISODD(ROW()*COLUMN()),SUM(A1:C1,A2,C2,A3:C3),INT(RAND()*8)+1)

Sample Output

enter image description here

\$\endgroup\$
1
\$\begingroup\$

Powershell, 149 148 bytes

-1 byte thanks to @AdmBorkBork. It's cool!

$i=-1
($a=(,1*8+0,1*3)*3+,1*7|%{$_*(1+(Random 9))})|?{++$i;!$_}|%{6..8+1|%{$_,-$_}|%{$a[$i]+=$a[$i+$_]}}
-join($a|%{if(!(++$i%7)){"
"};'{0,3}'-f$_})

Explanation:

$i=-1                       # let $i store -1
($a=                        # let $a is array of random numbers with zero holes
    (,1*8+0,1*3)*3+,1*7|    # the one-dimension array equals
                            # 1 1 1 1 1 1 1
                            # 1 0 1 0 1 0 1
                            # 1 1 1 1 1 1 1
                            # 1 0 1 0 1 0 1
                            # 1 1 1 1 1 1 1
                            # 1 0 1 0 1 0 1
                            # 1 1 1 1 1 1 1
    %{                      # for each element
        $_*(1+(Random 9))   # multiply 0 or 1 element to random digit from 1 to 9
    }                       # now $a stores values like (* is a random digit from 1 to 9)
                            # * * * * * * *
                            # * 0 * 0 * 0 *
                            # * * * * * * *
                            # * 0 * 0 * 0 *
                            # * * * * * * *
                            # * 0 * 0 * 0 *
                            # * * * * * * *
)|?{++$i;!$_                # calc index $i and passthru values == 0 only
}|%{                        # for each zero value cell with index $i
    6..8+1|%{               # offsets for the surrounding cells
                            #  .  .  .
                            #  .  x +1
                            # +6 +7 +8  
        $_,-$_              # add the mirror offsets 
                            # -8 -7 -6
                            # -1  x +1
                            # +6 +7 +8  
    }|%{                    # for each offset 
        $a[$i]+=$a[$i+$_]   # add surrounding values to the cell
    }
}
                            # display the $a
-join(
    $a|%{                   # for each value of $a
        if(!(++$i%7)){"`n"} # line break for each 7 cells
        '{0,3}'-f$_         # formatted value of $a with width = 3 char and align right
    }
)                           # join all values to string
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You can get rid of a byte (a newline) by encapsulating your $a assignment in parens and moving the next line up to make one big line -- ($a=(,1*8+0,1*3)*3+,1*7|%{$_*(1+(Random 9))})|?{++$i;!$_}|%{6..8+1|%{$_,-$_}|%{$a[$i]+=$a[$i+$_]}} \$\endgroup\$ Commented Aug 10, 2018 at 12:50
  • \$\begingroup\$ No. It doesn't work. The array must be fully populated before $a[$i+$_]. So here are two steps. I had several attempts to encapsulate in one pipe. :) \$\endgroup\$
    – mazzy
    Commented Aug 10, 2018 at 13:10
  • 1
    \$\begingroup\$ It doesn't work if you don't place parens around the assignment. With ($a=(,1*8+0,1*3)*3+,1*7|%{$_*(1+(Random 9))}), $a is fully populated before the next pipeline instance. It should work (at least, it does for me). \$\endgroup\$ Commented Aug 10, 2018 at 13:13
0
\$\begingroup\$

Mathematica 142 151 172 179

Code

z = (m = RandomInteger[{1, 9}, {7, 7}]; s = SparseArray; o = OddQ; e = EvenQ; i = {1, 1, 1};
(m + ArrayPad[ListCorrelate[{i, i, i}, m] s[{{i_, j_} /; o@i \[And] o@j -> 1}, {5, 5}], 1]
- 2 m s[{{i_, j_} /; e@i \[And] e@j -> 1}, {7, 7}]) // Grid)

Usage

z

m8

\$\endgroup\$
4
  • \$\begingroup\$ You have 0s; the rules say 1-9 \$\endgroup\$
    – Doorknob
    Commented Aug 31, 2013 at 18:29
  • \$\begingroup\$ Thanks. I corrected the data and pics. The functions remain unchanged. \$\endgroup\$
    – DavidC
    Commented Aug 31, 2013 at 18:43
  • \$\begingroup\$ Also, the numbers are not aligned as specified in the question. \$\endgroup\$
    – Doorknob
    Commented Aug 31, 2013 at 18:44
  • \$\begingroup\$ Mathematica's wordiness (or, more accurately, insistence on using big words) becomes apparent. \$\endgroup\$
    – DavidC
    Commented Aug 31, 2013 at 19:50
0
\$\begingroup\$

Julia 0.6, 127 (89) bytes

x=rand(1:9,7,7);[x[i,j]=sum(!(0==k==l)*x[i+k,j+l]for k=-1:1,l=-1:1)for i=2:2:7,j=2:2:7]
Base.showarray(STDOUT,x,1<1;header=1<1)

Try it online!

89 bytes using native display, which might be admissible if additional lines can be printed:

7×7 Array{Int64,2}:
6   6  8   2  3   2  3
7  44  5  33  4  23  5
3   8  1   9  1   3  2
4  41  2  37  5  22  2
7   8  8   8  3   4  2
9  53  6  44  7  36  3
7   7  1   9  2   6  9
\$\endgroup\$
0
\$\begingroup\$

Java 10, 262 260 248 239 bytes

v->{int a[][]=new int[7][7],i=49,j,k;for(;i-->0;)a[i/7][i%7]+=Math.random()*9+1;var r="";for(;++i<7;r+="\n")for(j=0;j<7;r+=(k=a[i][j])>9|j++%2<1?k+" ":k+"  ")if(i*j%2>0)for(a[i][j]=k=0;k<9;k++)a[i][j]+=k!=4?a[i+k/3-1][j+k%3-1]:0;return r;}

-12 bytes thanks to @ceilingcat.

Explanation:

Try it here.

v->{                        // Method with empty unused parameter and String return-type
  int a[][]=new int[7][7],  //  Integer-matrix with 7x7 zeroes
      i=49,j,k;             //  Index integers (`i` starting at 49)
  for(;i-->0;)              //  Loop `i` in the range (49, 0]:
    a[i/7][j%7]+=Math.random()*9+1;
                            //   Fill the current cell with a random 1..9 integer
  var r="";                 //  Result-String, starting empty
  for(;++i<7;               //  Loop `i` in the range [0, 7):
      r+="\n")              //    After every iteration: append a new-line to the result
    for(j=0;j<7;            //   Inner loop `j` in the range [0, 7):
        r+=                 //     After every iteration: append the result-String with:
           (k=a[i][j])>9    //      If the current number has 2 digits,
           |j++%2<1?        //      or it's an even column (indices 0/2/4/6)
            k+" "           //       Append the current number appended with one space
           :                //      Else:
            k+"  ")         //       Append the current number appended with two spaces
      if(i*j%2>1)           //    If both indexes `i` and `j` are odd
        for(a[i][j]=k=0;    //     Reset both the current item and index `k` to 0
            k<9;k++)        //     Inner loop `k` in the range [0, 9):
          a[i][j]+=         //      Sum the item at location `i,j` with:
           k!=4?            //       If `k` is not 4 (the current item itself)
            a[i+k/3-1][j+k%3-1]
                            //        Sum it with the numbers surrounding it
           :                //       Else:
            0;              //        Leave it the same by adding 0
  return r;}                //  Return the result-String
\$\endgroup\$
1
  • \$\begingroup\$ @ceilingcat Thanks! And I've been able to save a few more bytes with var instead of String and +=Math.random()*9+1; instead of =(int)(Math.random()*9+1);. It's actually pretty useful for you to visit all my old answers, haha! :D \$\endgroup\$ Commented Nov 26, 2019 at 10:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.