RosettaCodeData/Task/Cut-a-rectangle/Phix/cut-a-rectangle.phix

115 lines
3.6 KiB
Plaintext

integer show = 2, -- max number to show
-- (nb mirrors are not shown)
chance = 1000 -- 1=always, 2=50%, 3=33%, etc
sequence grid
integer gh, -- = length(grid),
gw -- = length(grid[1])
integer ty1, ty2, tx1, tx2 -- target {y,x}s
procedure mirror(integer y, x, ch)
-- plant/reset ch and the symmetric copy
grid[y,x] = ch
grid[gh-y+1,gw-x+1] = ch
end procedure
enum RIGHT, UP, DOWN, LEFT
constant dyx = {{0,+1},{-1,0},{+1,0},{0,-1}},
chx = "-||-"
function search(integer y, x, d, level)
integer count = 0
if level=0 or grid[y,x]!='x' then
mirror(y,x,'x')
integer {dy,dx} = dyx[d],
{ny,nx} = {y+dy,x+dx},
{yy,xx} = {y+dy*2,x+dx*3}
if grid[ny,nx]=' ' then
integer c = chx[d]
mirror(ny,nx,c)
if c='-' then
mirror(ny,nx+dx,c)
end if
integer meet = (yy=ty1 or yy=ty2) and (xx=tx1 or xx=tx2)
if meet then
count = 1
if show and rand(chance)=chance then
show -= 1
sequence g = grid -- (make copy/avoid reset)
-- fill in(/overwrite) the last cut, if any
if ty1!=ty2 then g[ty1+1,tx1] = '|'
elsif tx1!=tx2 then g[ty1][tx1+1..tx1+2] = "--"
end if
puts(1,join(g,'\n')&"\n\n")
end if
else
if grid[yy,xx]='+' then -- (minor gain)
for d=RIGHT to LEFT do -- (kinda true!)
count += search(yy,xx,d,level+1)
end for
end if
end if
mirror(ny,nx,' ')
if c='-' then
mirror(ny,nx+dx,' ')
end if
end if
if level!=0 then
-- ((level=0)==leave outer edges 'x' for next iteration)
mirror(y,x,'+')
end if
end if
return count
end function
function odd(integer n) return remainder(n,2)=1 end function
function even(integer n) return remainder(n,2)=0 end function
procedure make_grid(integer w,h)
-- The outer edges are 'x'; the inner '+' become 'x' when visited.
-- Likewise edges are cuts but the inner ones get filled in later.
sequence tb = join(repeat("x",w+1),"--"),
hz = join('x'&repeat("+",w-1)&'x'," ")&"\n",
vt = "|"&repeat(' ',w*3-1)&"|\n"
grid = split(tb&"\n"&join(repeat(vt,h),hz)&tb,'\n')
-- set size (for mirroring) and target info:
gh = length(grid) gw = length(grid[1])
ty1 = h+even(h) ty2 = ty1+odd(h)*2
tx1 = floor(w/2)*3+1 tx2 = tx1+odd(w)*3
end procedure
function side(integer w, h)
make_grid(w,h)
-- search top to mid-point
integer count = 0, last = 0
for r=3 to h+1 by 2 do
last = search(r,1,RIGHT,0) -- left to right
count += 2*last
end for
if even(h) then
count -= last -- (un-double the centre line)
end if
return count
end function
--atom t0 = time()
-- nb sub-optimal: obviously "grid" was designed for easy display, rather than speed.
for y=1 to 9 do -- 24s
--for y=1 to 10 do -- (gave up on >10x8)
for x=1 to y do
-- for x=1 to min(y,8) do -- 4 mins 16s (with y to 10)
if even(x*y) then
integer count = side(x,y)
if x=y then
count *= 2
else
count += side(y,x)
end if
printf(1,"%d x %d: %d\n", {y, x, count})
end if
end for
end for
--?elapsed(time()-t0)