```Here is my second solution.

Timings are on bottom but include size=15000 in under 5min. The way
this works is it starts with two solved 5x5 games with special
properties (end in center, and start on either the middle of the top,
or the middle of the left side -- pretty print them if that's
confusing). it then places as many of those as needed to fill the
entire board. it also has to deal with incrementing the numbers in
the original 2 patterns. i included some test code which makes sure
the final solution is valid.

The way placing the 5x5 pre-solved patterns works is i make a column
with a "left" on top and all the rest are the "up" variety. moving
from the middle of a 5x5 grid straight down takes you one square off
the grid, to they line up and all connect. now we're in the middle of
the bottom 5x5 pattern, so what we need is to move right and have
that transition to the next pattern, and then go back up to the top,
then back down again, etc to get the second variety of column which
goes back up, i just reversed the rows in the first column. before
combining the columns for the final solution, they are transposed to
be rows so I can just use +

maybe a better way to get a feel for how it works is to set the size
to 10 or 15 and pp the solution. then scan the answer for
1,25,26,50,51,75 etc to see how it's laid out

require "pp"
s = ARGV[0].to_i

if s <= 0
s = 165
end

if s % 5 != 0
puts "Invalid Input. Must be multiple of 5."
exit
end

Left = [[17, 9, 2, 18, 24], [4, 14, 22, 7, 13], [1, 19, 25, 10, 20],
[16, 8, 3, 15, 23], [5, 11, 21, 6, 12]]

Up = [[17, 4, 1, 16, 5], [9, 14, 19, 8, 11], [2, 22, 25, 3, 21], [18,
7, 10, 15, 6], [24, 13, 20, 23, 12]]

num = s / 5
\$items_in_a_column = 25 * num

\$inc_col_count = -\$items_in_a_column
def inc_col m
\$inc_col_count += \$items_in_a_column
m.map { |e| e.map { |e2| e2 + \$inc_col_count} }
end

\$inc_count = 0
def inc m
\$inc_count += 25
m.map { |e| e.map { |e2| e2 + \$inc_count} }
end

col = Left
(num-1).times do |j|
col += inc(Up)
end

col2 = col.reverse.transpose
col = col.transpose

sol = []

(num/2).times {sol +=  inc_col(col) + inc_col(col2)}

if num % 2 == 1
sol += inc_col(col)
end

# pp sol

# =========
# = tests =
# =========

Connections = [
[3,0],
[-3,0],
[0,3],
[0,-3],
[2,2],
[2,-2],
[-2,2],
[-2,-2]
]

def check_valid_movement m
flat = m.flatten
n = flat.length
rt_n = Math.sqrt(n).to_i
1.upto(n-1) do |i|
a = flat.index i
b = flat.index i+1
x1 = a % rt_n
y1 = a / rt_n
x2 = b % rt_n
y2 = b / rt_n
move = [x1-x2, y1-y2]
return false unless Connections.include? move
end
true
end

if true # warning: SLOW. took 9 minutes with size = 265. it's n^4 if
you treat the input number as n.
fail "dups" unless sol.flatten.uniq.length == sol.flatten.length
fail "invalid moves" unless check_valid_movement(sol)
puts "valid moves!"
end

__END__

cg5:~/cs/rb/quizzes >time ruby 90take3.rb 10000

real    1m34.483s
user    1m29.471s
sys     0m3.695s

cg5:~/cs/rb/quizzes >time ruby 90take3.rb 15000

real    4m47.336s
user    4m30.390s
sys     0m11.935s

cg5:~/cs/rb/quizzes >time ruby 90take3.rb 25000

real    23m0.525s
user    21m47.343s
sys     0m50.721s

26700 = gave up after 45min, incomplete. 30000 = gave up after 3
hours, incomplete.

```