import copy,pprint
import traceback
from split_utils import dist

def flatten(startsol):
    res=[]
    while len(startsol):
        more=startsol.pop(0)
        res.extend(more)
    return res
    
    
def setit(rows,pos):
    assert rows[pos[1]][pos[0]]==0
    rows[pos[1]][pos[0]]=1
    return rows

def isopen(rows,pos):
    return not rows[pos[1]][pos[0]]

def row2room(rows,pos):
    rooms=[]
    r=(pos[0]+1,pos[1])
    ro=isopen(rows,r)
    l=(pos[0]-1,pos[1])
    lo=isopen(rows,l)
    
    if ro or lo:
        u=(pos[0],pos[1]-1)
        uo=isopen(rows,u)
        d=(pos[0],pos[1]+1)
        do=isopen(rows,d)
    if ro:
        if uo:
            ur=(pos[0]+1,pos[1]-1)
            if isopen(rows,ur):
                rooms.append([pos,u,r,ur])
        if do:
            dr=(pos[0]+1,pos[1]+1)
            if isopen(rows,dr):
                rooms.append([pos,d,r,dr])
    if lo:
        if uo:
            ul=(pos[0]-1,pos[1]-1)
            if isopen(rows,ul):
                rooms.append([pos,u,l,ul])
        if do:
            dl=(pos[0]-1,pos[1]+1)
            if isopen(rows,dl):
                rooms.append([pos,d,l,dl])
    return rooms


def getroom(rows,pos,thisroom,checked):
    """returns all connected room squares,_"""
    checked.add(pos)
    for rt in row2room(rows,pos):
        thisroom.update(rt)
    tocheck=thisroom.difference(checked)
    while len(tocheck):
        this=tocheck.pop()
        thisroom,checked=getroom(rows,this,thisroom,checked)
        tocheck=[c for c in thisroom if c not in checked]
    return thisroom,checked


def convert2(pos,rows):
    convertdebug=0
    sqs,_=getroom(rows,pos,set([]),set([]))
    if not sqs:
        return set([]),[]
    touching=[]
    edges=set([])
    tunnels=[]
    if convertdebug:print 'RMsqs',sqs
    
    while 1:
        if convertdebug:print 'start of loop; sqs is:',sorted(sqs)
        gotnew=False
        n=None
        for sq in sqs:
            if not isopen(rows,sq):continue
            for n in orth(sq):
                if not isopen(rows,n):continue
                if n in sqs:continue
                if len(getopendvs(rows,n))==2:
                    gotnew=True
                    if convertdebug:print 'got new alley:',n
                    break
            if gotnew:
                break
        
        
        if gotnew:
            oldsqs=copy.deepcopy(sqs)
            sqs,_=getroom(rows,n,sqs,sqs)
            if convertdebug:print 'from N:',n
            if convertdebug:print 'gained pos:',sqs.difference(oldsqs)
            continue
        if convertdebug:print 'alley checking done, for now...'
        #then check for 2 edges in the same room.
        edges=set([])
        edgerooms=set([])
        for s in sqs:
            edges.update([n for n in orth(s) if n not in sqs and isopen(rows,n)])
        for e in edges:
            #only grab the next room if doubly connected to it.
            if convertdebug:print 'checking edge e:',
            rm,_=getroom(rows,e,set([]),set([]))
            if convertdebug:print 'rm:',rm,
            if convertdebug:print 'edgerooms',edgerooms
            if rm.intersection(edgerooms):
                if convertdebug:print 'BANG!adding',sorted(rm)
                gotnew=True
                sqs.update(rm)
                break
            edgerooms.update(rm)
        if not gotnew:
            break
            
#~     remsqs=[]
#~     for s in sqs:
#~         sin=[n for n in orth(s) if isopen(rows,n) and n in sqs]
#~         if len(sin)==1:
#~             remsqs.append(s)
#~     for s in remsqs:sqs.remove(s)
#~     print 'removed to be alley squares:',remsqs
#~     edges=set([])
#~     for s in sqs:
#~         edges.update([n for n in orth(s) if n not in sqs and isopen(rows,n)])
    if convertdebug:print 'finally, sqs is:',sorted(sqs)
    if convertdebug:print 'and edges:',sorted(edges)
    
        
        
#~             for n in [n for n in orth(sq) if isopen(rows,n) and n not in sqs]:
#~                 if gettunnel(rows,n):
#~                     tunnels.append(gettunnel(rows,n))
#~     for s in sqs:
#~         if getopendvs(rows,s)==2:
#~             remsqs.append(s)
#~     print 'removing:',remsqs
#~     for s in remsqs:
#~         sqs.remove(s)
#~     if convertdebug:print 'sqs update with tunnel squares.',sorted(sqs)
#~     for s in sorted(sqs):
#~         if convertdebug:print s,'has edges:',[n for n in orth(s) if n not in sqs and isopen(rows,n)]
#~         edges.update([n for n in orth(s) if n not in sqs and isopen(rows,n)])
#~             
#~     if convertdebug:print 'edges updated:',edges
#~     alledgerooms=set([])
#~     broke=False
#~     print 'first time through.'
#~     while 1:
#~         badedges=[]
#~         for e in edges:
#~             if e in sqs:
#~                 badedges.append(e)
#~         for b in badedges:
#~             print 'removed edge:',b
#~             edges.remove(b)
#~         for e in edges:
#~             if len(getopendvs(rows,e))!=2:
#~                 print 'not extending from:',e,'with',len(getopendvs(rows,e))
#~                 continue
#~             edgeroom,_=getroom(rows,e,set([]),set([]))
#~             print 'got edgeroom:',edgeroom
#~             if alledgerooms.intersection(edgeroom):
#~                 print 'intersected! so adding this whole damn room',alledgerooms.intersection(edgeroom)
#~                 sqs.update(edgeroom)
#~                 broke=True
#~                 break
#~             alledgerooms.update(edgeroom)
#~             print 'new alleged rooms:',alledgerooms
#~         if not broke:
#~             break
#~         for e in edgeroom:
#~             edges.update([n for n in orth(e) if n not in sqs and isopen(rows,n)])
#~         
#~             
    if convertdebug:print '++++++++++edges are now done!',edges,'making touching.'
    for e in edges:
        if convertdebug:print 'edge:',e,'has neighborcount:',
        neighborcount=len([n for n in orth(e) if isopen(rows,n) and n not in sqs])
        if convertdebug:print neighborcount
        touching.append((e,neighborcount))
    
    touchsqs=[t[0] for t in touching]
    if convertdebug:print '==============VERFY'
#~     for t in touching:
#~         if convertdebug:print t
#~         sqneighbors=[sq for sq in sqs if dist(sq,t[0])==1]
#~         if convertdebug:print 'sqneighbors',sqneighbors
#~         tneighbors=[ot for ot in touching if dist(t[0],ot[0])==1]
#~         if convertdebug:print 'tneighbors',tneighbors
#~         if len(sqneighbors)+len(tneighbors)>1:
#~             removed.append(t)
#~     for r in removed:
#~         touching.remove(r)
#~         sqs.add(r[0])
#~     if convertdebug:print 'remved:',removed
    if convertdebug:print 'touchign after!',sorted(touching)    
    if convertdebug:print 'sqs:',sqs
    if convertdebug:print 'sqs',sorted(sqs)
    if convertdebug:print 'touching:',sorted(touching    )
    return sqs,touching
    



def convert(pos,rows):
    convertdebug=0
    sqs,_=getroom(rows,pos,set([]),set([]))
    if not sqs:
        return set([]),[]
    touching=[]
    edges=set([])
    tunnels=[]
    if convertdebug:print 'RMsqs',sqs
    edges=set([])
    edgealleys=set([])
    for s in sorted(sqs):
        if convertdebug:print s,'has edges:',[n for n in orth(s) if n not in sqs and isopen(rows,n)]
        edges.update([n for n in orth(s) if n not in sqs and isopen(rows,n)])
    while 1:
        got=False
        for e in edges:
            tun=gettunnel(rows,e)
            if tun.intersection(edgealleys):
                sqs.update(tun)
                got=True
        if not got:break
    
    edges=[e for e in edges if e not in sqs]
    for e in edges:
        if convertdebug:print 'edge:',e,'has neighborcount:',
        neighborcount=len([n for n in orth(e) if isopen(rows,n) and n not in sqs])
        if convertdebug:print neighborcount
        touching.append((e,neighborcount))
    
    return sqs,touching
    
    
    
    while 1:
        if convertdebug:print 'start of loop; sqs is:',sorted(sqs)
        gotnew=False
        n=None
        for sq in sqs:
            if not isopen(rows,sq):continue
            for n in orth(sq):
                if not isopen(rows,n):continue
                if n in sqs:continue
                if len(getopendvs(rows,n))==2:
                    gotnew=True
                    if convertdebug:print 'got new alley:',n
                    break
            if gotnew:
                break
        
        
        if gotnew:
            oldsqs=copy.deepcopy(sqs)
            sqs,_=getroom(rows,n,sqs,sqs)
            if convertdebug:print 'from N:',n
            if convertdebug:print 'gained pos:',sqs.difference(oldsqs)
            continue
        if convertdebug:print 'alley checking done, for now...'
        #then check for 2 edges in the same room.
        edges=set([])
        edgerooms=set([])
        for s in sqs:
            edges.update([n for n in orth(s) if n not in sqs and isopen(rows,n)])
        for e in edges:
            #only grab the next room if doubly connected to it.
            if convertdebug:print 'checking edge e:',
            rm,_=getroom(rows,e,set([]),set([]))
            if convertdebug:print 'rm:',rm,
            if convertdebug:print 'edgerooms',edgerooms
            if rm.intersection(edgerooms):
                if convertdebug:print 'BANG!adding',sorted(rm)
                gotnew=True
                sqs.update(rm)
                break
            edgerooms.update(rm)
        if not gotnew:
            break
         
#~     for s in sorted(sqs):
#~         if convertdebug:print s,'has edges:',[n for n in orth(s) if n not in sqs and isopen(rows,n)]
#~         edges.update([n for n in orth(s) if n not in sqs and isopen(rows,n)])
#~             
#~     if convertdebug:print 'edges updated:',edges
#~     alledgerooms=set([])
#~     broke=False
#~     print 'first time through.'
#~     while 1:
#~         badedges=[]
#~         for e in edges:
#~             if e in sqs:
#~                 badedges.append(e)
#~         for b in badedges:
#~             print 'removed edge:',b
#~             edges.remove(b)
#~         for e in edges:
#~             if len(getopendvs(rows,e))!=2:
#~                 print 'not extending from:',e,'with',len(getopendvs(rows,e))
#~                 continue
#~             edgeroom,_=getroom(rows,e,set([]),set([]))
#~             print 'got edgeroom:',edgeroom
#~             if alledgerooms.intersection(edgeroom):
#~                 print 'intersected! so adding this whole damn room',alledgerooms.intersection(edgeroom)
#~                 sqs.update(edgeroom)
#~                 broke=True
#~                 break
#~             alledgerooms.update(edgeroom)
#~             print 'new alleged rooms:',alledgerooms
#~         if not broke:
#~             break
#~         for e in edgeroom:
#~             edges.update([n for n in orth(e) if n not in sqs and isopen(rows,n)])
#~         
#~             
    if convertdebug:print '++++++++++edges are now done!',edges,'making touching.'
    for e in edges:
        if convertdebug:print 'edge:',e,'has neighborcount:',
        neighborcount=len([n for n in orth(e) if isopen(rows,n) and n not in sqs])
        if convertdebug:print neighborcount
        touching.append((e,neighborcount))
    
    touchsqs=[t[0] for t in touching]
    if convertdebug:print '==============VERFY'
#~     for t in touching:
#~         if convertdebug:print t
#~         sqneighbors=[sq for sq in sqs if dist(sq,t[0])==1]
#~         if convertdebug:print 'sqneighbors',sqneighbors
#~         tneighbors=[ot for ot in touching if dist(t[0],ot[0])==1]
#~         if convertdebug:print 'tneighbors',tneighbors
#~         if len(sqneighbors)+len(tneighbors)>1:
#~             removed.append(t)
#~     for r in removed:
#~         touching.remove(r)
#~         sqs.add(r[0])
#~     if convertdebug:print 'remved:',removed
    if convertdebug:print 'touchign after!',sorted(touching)    
    if convertdebug:print 'sqs:',sqs
    if convertdebug:print 'sqs',sorted(sqs)
    if convertdebug:print 'touching:',sorted(touching    )
    return sqs,touching













class Room:
    def __init__(self,pos,rows,levelnum=None):
        if levelnum is None:levelnum='test'
        
        self.levelnum=levelnum
        sqs,touching=convert(pos,rows)
        
        self.miny=min(s[1] for s in sqs)-1
        self.minx=min(s[0] for s in sqs)-1
        self.maxy=max(s[1] for s in sqs)+1
        self.maxx=max(s[0] for s in sqs)+1
        touching=[((t[0][0]-self.minx,t[0][1]-self.miny),t[1]) for t in touching]
        sqs=[(s[0]-self.minx,s[1]-self.miny) for s in sqs]
        self.sqs=sqs
        self.touching=touching
        self.touchsqs=[t[0] for t in touching]
        self.roomname=','.join(['('+str(s[0])+','+str(s[1])+')' for s in sorted(sqs)])
        self.roomname+='t'.join([str(t) for t in sorted(touching)])
        self.req=[sq[0] for sq in touching if sq[1]==1]
        self.opt=[sq[0] for sq in touching if sq[1]!=1]
        self.rows=[]
        self.marker=2
        assert len(sqs)>3,sqs
        
        for yy in range(self.maxy-self.miny+2):
            row=[]
            for xx in range(self.maxx-self.minx+2):
                p=(xx,yy)
                if p in self.opt:
                    row.append(0)
                elif p in self.req:
                    row.append(0)
                elif p in sqs:
                    row.append(0)
                else:
                    row.append(1)
            self.rows.append(row)
        self.ins,self.outs=[],[]
        self.either=self.touching[:]
        self.width=len(self.rows[0])
        self.height=len(self.rows)
        
    def show(self):
        print  ''
        for yy in range(self.height):
            row=''
            for xx in range(self.width):
                p=(xx,yy)
                
                if isopen(self.rows,p):
                    if p in self.opt:
                        row+='*'
                    elif p in self.req:
                        row+=chr(177)
                    else:
                        row+='0'
                else:
                    try:
                        row+=str(self.rows[yy][xx])
                    except:
                        row+='1'
            print row
            
    def fastmove(self,pos,dv):
        assert self.isclosed(pos),'pos was'+str(pos)+'dv was:'+str(dv)
        next=add(pos,dv)
        assert self.isopen(next)
        
        covered=[]
        while self.isopen(next):
            pos=next
            covered.append(pos)
            next=add(pos,dv)
            if pos in self.touchsqs:
                break
                
        return pos,covered
        
    def multimove(self,pos,dv,remaining_entries):
        if dv is 'skip':
            self.coverstore.append([])
            return pos,[]
        if roomdebug:print  'multimove! pos',pos,'dv',dv
        multimove=[]
        multicover=[]
        while 1:
            if roomdebug:print  'fastmoving from pos',pos,'dv'
            pos,covered=self.fastmove(pos,dv)
            if roomdebug:print  'after fastmove: pos',pos,'covered',covered
            multimove.append(dv)
            multicover.extend(covered)
            
            self.set_many(covered)
            if roomdebug:print  'setting:',covered
            dv=self.pos2dv(pos)
            if pos in remaining_entries:
                if roomdebug:print  'reached touching!!'
                break
            if len(dv)!=1:
                break
            dv=dv[0]
            
        self.coverstore.append(multicover)
        if roomdebug:print  'multimove end, returning pos:',pos,'multimove',multimove
        
        if roomdebug:print 'end of mlutimove; pso',pos,':isopen:',self.isopen(pos)
        if roomdebug:print 'coverstore :',self.coverstore
        if roomdebug:print 'remaining entries:',remaining_entries
        if roomdebug:self.show()
        if roomdebug:print '=========\n'
        return pos,multimove
    
    def doneok(self):
        for r in self.rows:
            if 0 in r:
                return False
        return True
    
    def fork(self,allsol,pos,origdv,remaining_entries,thisentry,this_entry_sol=[]):
        if roomdebug:print "===================FORK="
        if roomdebug:print  'start of fork. pos:',pos,'origdv',origdv,'with remaining entries',remaining_entries
        if roomdebug:print  'coverstore is:',self.coverstore
        if roomdebug:print  'this entry sol:',this_entry_sol
        if roomdebug:print  'allsol:',allsol
        pos,sol=self.multimove(pos,origdv,remaining_entries)
        if roomdebug:self.show()
        if roomdebug:print  'did multimove, pos:',pos,'sol:',sol
        if roomdebug:print  'did multimove, remaining entries;',remaining_entries    
        this_entry_sol.append(sol)
        
        
        if pos in remaining_entries or origdv is 'skip':
            allsol.append((thisentry,this_entry_sol,pos))
            nowremaining=remaining_entries[:]
            if pos in remaining_entries :
                
                if roomdebug:print 'copied rem ent to nowrem:',sorted(nowremaining)
                nowremaining.remove(pos)
                
                if roomdebug:print 'and removed:',pos
            
            
            if nowremaining:
                
                for r in nowremaining:
                    rdvs=[dv for dv in self.pos2dv(r) if add(r,dv) not in self.touchsqs]
                    if r in self.opt:
                        rdvs.append('skip')
                    rem=nowremaining[:]
                    if roomdebug:print 'nowremaining is:',nowremaining
                    if roomdebug:print 'rem is:',rem
                    if roomdebug:print 'removing r:',r
                    rem.remove(r)
                    if roomdebug:print 'rdvs are:',rdvs,'for r:',r
                    for rdv in rdvs:
                        prerem=rem[:]
                        self.marker+=1
                        if roomdebug:print 'forking on r:',r
                        self.set(r)
                        if roomdebug:print 'inner fork setting...',r
                        self.fork(allsol,r,rdv,rem,r,[])
                        if roomdebug:print 'inner fork backtrack unsetting...',r
                        self.unset(r)
                        self.marker-=1
                        rem=prerem
            else:
                if self.doneok():
                    if roomdebug:print  '+++++++++++board was doneOK!'
                    if roomdebug:print  'thisentry:',thisentry
                    if roomdebug:print  'this entry sol:',this_entry_sol
                    if roomdebug:print  'allsol:',allsol
                    self.ultrasols.append(copy.deepcopy(allsol))
                    if roomdebug:print  'ultrasols:::',self.ultrasols
                    
                #restore
                else:
                    if roomdebug:print  '----------not doneOK'
            allsol.pop()
        
        if pos in self.touchsqs:
            nextdvs=[n for n in self.pos2dv(pos) if add(pos,n) not in self.touchsqs]
            #~ print 'touchsqs:',self.touchsqs
            if roomdebug:print 'now pos:',pos,'am at touching, so next dvs are only:',nextdvs
            if roomdebug:print 'instead of:',self.pos2dv(pos)
        else:
            nextdvs=self.pos2dv(pos)
        
        #fork again after choice while moving
        if origdv !='skip':
            for dv in nextdvs:
                if roomdebug:print  'forking on dv:',dv
                if roomdebug:self.show()
                assert not (pos in self.touchsqs and add(pos,dv) not in self.touchsqs)
                self.fork(allsol,pos,dv,remaining_entries,thisentry,this_entry_sol)
            
        
        #restore
        uncover=self.coverstore.pop()
        if roomdebug:print  'NO more DVS<<<<<<<<<<<backing up; uncover:',uncover
        self.unset_many(uncover)
        this_entry_sol.pop()
        
    
            


    def sol2img(self,roomsol,return_im=False,return_dict=False):
        inout={}
        last='S'
        rows=copy.deepcopy(self.rows)
        for s in roomsol:
            now,startsol,endpos=s
#~             print 'now;',now,'startsol',startsol,'endpos',endpos
            startsol=flatten(startsol)
            if roomdebug:print 'startsol now:',startsol
            for r in rows:
                if roomdebug:print r
            if roomdebug:print 'setting',now
            rows=setit(rows,now)
            inout[now]=['s']
            while len(startsol):
                thisdv=startsol.pop(0)
                if roomdebug:print 'thisdv:',thisdv
                from admin import getd
                thisd=getd(thisdv).lower()
                next=add(now,thisdv)
                while isopen(rows,next):
                    inout[now].append(thisd)
                    now=next
                    rows=setit(rows,now)
                    inout[now]=[thisd]
                    next=add(now,thisdv)
        image_dict={}
        for k,v in inout.items():
            if v==['s']:
                v='skip'
            if len(v)==1:
                v='out'
            image_dict[k]=''.join(v)
#~         print  'img dict for sol:',roomsol
        if return_dict:
            return image_dict
        worktype='roomsol%04d'%self.levelnum
        'making unique name for a room!'
        nm=','.join([image_dict.get(s,'none') for s in sorted(self.sqs)])+'t'.join([image_dict.get(t[0],'nonet') for t in sorted(self.touching)])
        sqvals=image_dict.items()
        sqvals.sort()
        fname=worktype+' '+rm.roomname+','+nm
        imgtext=None
        from admin import pshow
        if return_im:
            return pshow(rows=rows,return_im=return_im,fname=fname,imgtext=imgtext,image_dict=image_dict,worktype=worktype,overwrite=True)
        else:
            pshow(rows=rows,fname=fname,overwrite=False,imgtext=imgtext,image_dict=image_dict,worktype=worktype,overwrite=True)

    def solve(self):
        self.ultrasols=[]
        self.coverstore=[]
        for pos,ns in self.touching:
            if roomdebug:print  'trying:',pos,'with neighbors:',ns
            dvs=[dv for dv in self.pos2dv(pos) if add(pos,dv) not in self.touchsqs]
            if roomdebug:print  'dvs::',dvs
            indv=dvs[0]
            self.set(pos)
            remaining_entries=[t[0] for t in self.touching]
            
            remaining_entries.remove(pos)
            if roomdebug:print  'remaining entries:',remaining_entries
            if roomdebug:print "FIRSTFORK=========================================",pos
            self.fork([],pos,indv,remaining_entries,pos)
            self.unset(pos)
        import pprint
        if roomdebug:pprint.pprint(self.ultrasols)
        for sol in self.ultrasols:
            if roomdebug:print  sol,
            sol=cleansol(sol)
            if roomdebug:print  'cleaned::',sol
            self.sol2img(copy.deepcopy(sol))
            #~ print "HHHHHHHH"
            if roomdebug:print  'cleaned::',sol
            
           
    def getopen_pos(self,pos):
        return [p for p in orth(pos) if self.isopen(p)]
            
    def pos2dv(self,pos):
        return [n for n in range(4) if self.isopen(add(pos,n))]

    def isclosed(self,pos):
        return self.rows[pos[1]][pos[0]]!=0
        
    def isopen(self,pos):
        return not self.isclosed(pos)
    
    def set(self,pos):
        assert self.rows[pos[1]][pos[0]]==0 , ('actually '+str(pos)+'is'+str(self.rows[pos[1]][pos[0]]))
        self.rows[pos[1]][pos[0]]=self.marker

    def set_many(self,many):
        for m in many:
            self.set(m)
            
    def unset(self,pos):
        assert self.rows[pos[1]][pos[0]]!=0
        self.rows[pos[1]][pos[0]]=0

    def unset_many(self,many):
        for m in many:
            self.unset(m)

def gettunnel(rows,pos,seen=None):
    if seen is None:
        return gettunnel(rows,pos,set([]))
    if pos in seen:
        return seen
    dvs=getopendvs(rows,pos)
    if len(dvs)>2:
        return seen
    seen.add(pos)
    for dv in dvs:
        seen.update(gettunnel(rows,add(pos,dv),seen))
        next=add(pos,dv)
    return seen

def getopendvs(rows,pos):
    assert isopen(rows,pos)
    return [n for n in range(4) if isopen(rows,add(pos,n))]

def cleansol(sol):
    return [s for s in sol if s[1]]

def add(loc,dv):
    dv=dv%4
    if dv==0:
        return (loc[0]+1,loc[1])
    if dv==1:
        return (loc[0],loc[1]+1)
    if dv==2:
        return (loc[0]-1,loc[1])
    else:
        return (loc[0],loc[1]-1)

def orth(pos):
    return [add(pos,n) for n in range(4)]   

def show(rows):
    for r in rows:
        l=''.join(str(n) for n in r)
        print l
        
from admin import loadrows
import config

import psyco
psyco.full()

levelnum=89
rows=loadrows(levelnum)
config.maxx,config.maxy=len(rows[0])-1,len(rows)-1
done=set([])
from split_utils import innerboard
roomdebug=0
do_one=0
target_pos=(5,18)
if do_one:
    roomdebug=1
from admin import pshow

worktype='roomsol%04d'%levelnum
fname=worktype+'%04d'%levelnum
import psyco
psyco.full()
all_img_dict={}
for ii,pos in enumerate(innerboard(config)):
    x,y=pos
    if do_one:
        pos=target_pos
    if not isopen(rows,pos):
        continue
    
    if pos in done:continue
    print 'OPEN:::::::::::',
    print ii,'/',pos
    try:
        if do_one:
            for yy in range(max(pos[1]-10,0),min(pos[1]+10,config.maxy)):
                print '%03d'%yy,'===>',
                l=''
                for xx in range(max(pos[0]-10,0),min(pos[0]+10,config.maxx)):
                    l+=str(rows[yy][xx])
                print l
        
        sqs,touching=convert(pos,rows)
        if not sqs:continue
        print 'got sqsssssssss',sorted(sqs)
        special_dict={}
        for s in sqs:
            special_dict[s]='blue'
        for t in touching:
            print t
            if t[1]==1:
                special_dict[t[0]]='red'
            else:
                special_dict[t[0]]='yellow'
        worktype='roomsol%04d'%levelnum
        pshow(fname='text'+str(pos),rows=rows,special_dict=special_dict,worktype=worktype)
        done.update(sqs)
        rm=Room(pos,rows,levelnum)
        rm.show()
        #~ print 'got sqs:',rm.sqs
        #~ print 'touching:',rm.touching
        #~ continue
        res=rm.solve()
        
    except:
        traceback.print_exc()
    print 'ultrasols:',len(rm.ultrasols)
    
    try:
        if len(rm.ultrasols)==1:
            print 'have only one ultrasol!! getting img dict.',rm.ultrasols,rm.ultrasols[0]
            p_img_dict=rm.sol2img(rm.ultrasols[0],return_dict=True)
            adjusted={}
            for k,v in p_img_dict.items():
                assert (k[0]+rm.minx,k[1]+rm.miny) not in adjusted
                if 's' in v:continue
                if v in 'out skip'.split():continue
                adjusted[(k[0]+rm.minx,k[1]+rm.miny)]=v
            #~ print 'pimgdict:'
            #~ pprint.pprint(p_img_dict)
            #~ print 'adjusted::'
            #~ pprint.pprint(adjusted)
            
            all_img_dict.update(adjusted)
    except:
        traceback.print_exc()
        
    if len(rm.ultrasols)==0:
        print 'WHOAH!'
        import time
    if do_one:break
print 'finally got all img dict:'
pprint.pprint(all_img_dict)

pshow(rows=rows,image_dict=all_img_dict,overwrite=True,worktype=worktype,fname=fname)