Игра Реверси (Lua)


* Алгоритм можно усилить

#!/usr/bin/env lua

-- Copyright (C) Igor Salnikov 2015 --

local SX=8
local SY=8
local FIELD={}

function n2pos(n)
    return {
        x = (n-1) % SX + 1,
        y = math.floor((n-1) / SX) + 1
    }
end

function pos2n(p)
    if (p.x<1) or (p.x>SX) or (p.y<1) or (p.y>SY) then
        return -1
    end
    return ((p.y-1) * SX + p.x)
end

function plus(n,d)
    p = n2pos(n)
    p.x = p.x + d.x
    p.y = p.y + d.y
    return pos2n(p)
end

function walk_invert(fig,n,d)
    local r=false
    if not on_field(n) then
        r=false
    elseif get_figure(n).fig==0 then
        r=false
    elseif get_figure(n).fig==fig then
        r=true
    elseif walk_invert(fig,plus(n,d),d) then
        set_figure(n, {fig=get_figure(n).fig, mark=1}, false)
        r=true
    end
    return r
end
    

function invert(f,n)
    walk_invert(f,plus(n,{x=-1,y=-1}),{x=-1,y=-1});
    walk_invert(f,plus(n,{x=-1,y= 0}),{x=-1,y= 0});
    walk_invert(f,plus(n,{x=-1,y= 1}),{x=-1,y= 1});
    walk_invert(f,plus(n,{x=0, y=-1}),{x=0, y=-1});
    walk_invert(f,plus(n,{x=0, y= 1}),{x=0, y= 1});
    walk_invert(f,plus(n,{x=1, y=-1}),{x=1, y=-1});
    walk_invert(f,plus(n,{x=1, y= 0}),{x=1, y= 0});
    walk_invert(f,plus(n,{x=1, y= 1}),{x=1, y= 1});
    for p=1, SX*SY do
        if get_figure(p).mark==1 then
            set_figure(p,{fig=f,mark=0},false)
        end
    end
end

function set_figure(n, F, inv)
    FIELD[n] = F
    if inv==true then
        invert(F.fig, n)
    end
end

function get_figure(n)
    return FIELD[n]
end

function on_field(n)
    return (n>=1) and (n<=SX*SY);
end

function figure(fig)
    local r = '.'
    if fig==1 then r='B' elseif fig==-1 then r='r' end
    return r
end

function field_power(n)
    local p=n2pos(n)
    if (p.x==1) or (p.x==SX) or (p.y==1) or (p.y==SY) then
        return 2
    end
    return 1
end

function get_new_pos(F)
    local max_p = 0
    local max_count = 0
    local max_save = {}
    for n=1, SX*SY do
        if get_figure(n).fig==0 then
            local p=pos_power(F.fig, n)
            fp = 0
            if p>0 then fp = field_power(n) end
            if (p>0) and ((fp+p)>max_p) then
                max_p = p+fp
                max_count = max_count + 1
                max_save[max_count] = n
            end
        end
    end
    for n=1, SX*SY do
        if get_figure(n).fig==0 then
            local p=pos_power(F.fig, n)
            fp = 0
            if p>0 then fp = field_power(n) end
            if (p==max_p) then
                max_count = max_count + 1
                max_save[max_count] = n
            end
        end
    end
    return max_save[math.random(max_count)]
end

function walk(fig,n,d)
    local r = 0
    while true do
        if not on_field(n) then
            r=0; break;
        end
        if get_figure(n).fig==0 then
            r=0; break;
        end
        if get_figure(n).fig==fig then
            break
        end
        r=r+1
        n=plus(n,d)
    end
    return r
end

function pos_power(fig, n)
    return (
        walk(fig, plus(n,{x=-1,y=-1}), {x=-1,y=-1}) +
        walk(fig, plus(n,{x=-1,y= 0}), {x=-1,y= 0}) +
        walk(fig, plus(n,{x=-1,y= 1}), {x=-1,y= 1}) +
        walk(fig, plus(n,{x= 0,y=-1}), {x= 0,y=-1}) +
        walk(fig, plus(n,{x= 0,y= 1}), {x= 0,y= 1}) +
        walk(fig, plus(n,{x= 1,y=-1}), {x= 1,y=-1}) +
        walk(fig, plus(n,{x= 1,y= 0}), {x= 1,y= 0}) +
        walk(fig, plus(n,{x= 1,y= 1}), {x= 1,y= 1})
    )
end

function has_pos(F)
    local r=false
    for n=1,SX*SY do
        if (get_figure(n).fig==0) and (pos_power(F.fig,n)>0) then
            r=true
            break
        end
    end
    return r
end

function setup()
    math.randomseed(os.time())
    for n=1,SX*SY do
         set_figure(n, {fig=0,mark=0}, false)
    end
    set_figure(pos2n({x=4,y=4}),{fig=1,mark=0})
    set_figure(pos2n({x=5,y=5}),{fig=1,mark=0})
    set_figure(pos2n({x=4,y=5}),{fig=-1,mark=0})
    set_figure(pos2n({x=5,y=4}),{fig=-1,mark=0})
end

function stat()
    b=0; r=0;
    for n=1,SX*SY do
        if get_figure(n).fig==1 then b=b+1
            elseif get_figure(n).fig==-1 then r=r+1
        end
    end
    print('B='..b..', R='..r)
end

function show()
    for n=1,SX*SY do
        io.write( figure(get_figure(n).fig) )
        if n % SX == 0 then print() end
    end
    stat()
    print()
end

function OnClick(n)
    if pos_power(1,n)>0 then
        set_figure(n,{fig=1,mark=0},true)
        show()
        --Pause
        --SetLock(true)
        --CopyField()
        local wait=false
        while has_pos({fig=-1}) do
            n=get_new_pos({fig=-1})
            set_figure(n,{fig=-1,mark=0},true)
            if has_pos({fig=1}) then
                wait=true
                break
            end
            print('ONE MORE')
        end
        --SetLock(false)
        --if not wait then TheEnd end
    end
end

setup()
show()
local n=1

while has_pos({fig=1}) do
    print('CYCLE='..n)
    OnClick(get_new_pos({fig=1}))
    show()
    n=n+1
end