# Story

Old MacDingle had a farm... 

...and on that farm he had

* horses 
* chickens 
* rabbits 
* some apple trees
* a vegetable patch

Everything is idylic in the MacDingle farmyard **unless somebody leaves the gates open**

Depending which gate was left open then...

* horses might run away
* horses might eat the apples
* horses might eat the vegetables
* chickens might run away
* rabbits might run away
* rabbits might eat the vegetables

# Kata Task

Given the state of the farm gates in the evening, your code must return what the farm looks like the next morning when daylight reveals what the animals got up to.

# Legend

* ```H``` horse
* ```C``` chicken
* ```R``` rabbit
* ```A``` apple tree
* ```V``` vegetables
* ```|``` gate (closed), 
* ```\``` or ```/``` gate (open)
* ```.``` everything else

# Example


Before
```|..HH....\AAAA\CC..|AAA/VVV/RRRR|CCC```

After
```|..HH....\....\CC..|AAA/.../RRRR|...```
Because:

The horses ate whatever apples they could get to
The rabbits ate the vegetables
The chickens ran away




# Notes

* If the animals can eat things *and* also run away then they do **BOTH** - it is best not to run away when you are hungry!
* An animal cannot "go around" a closed gate...
* ...but it is possible to run away from the farm and then **RUN BACK** and re-enter though more open gates on the other side!

Difficulty: introductory

Starter code:

def shut_the_gate(farm):
	

Solutions:
from itertools import groupby
def shut_the_gate(farm):
    who_eats_whom = {'H': ['A', 'V'], 'R': ['V'], 'C': []}
    runaway_back ,runaway_front, farm = [], [], ["".join(j) for k, j in groupby(farm)]
    def doSomeFarm(i=0):
        def do(j,s=False):
            while (j >= 0 if s else j<len(farm)) and farm[j] != '|':
                if farm[j][0] in who_eats_whom[current[0]] : farm[j] = '.' * len(farm[j])
                j += [1,-1][s]
            return j
        while i < len(farm):
            current = farm[i]
            if current[0] in who_eats_whom:
                r,r1 = do(i,1),do(i)
                if r == -1 or r1 == len(farm):
                    farm[i] = '.' * len(farm[i])
                    [runaway_front,runaway_back][r!=-1].append(current[0])
            i += 1
    doSomeFarm()
    l = len(runaway_back)
    if l:
        if farm[0] != '|':
            farm = ['/'] + " / ".join(runaway_back[::-1]).split() + farm
            doSomeFarm()
            farm = farm[l * 2:]
    l = len(runaway_front)
    if l:
        if farm[-1] != '|':
            farm = farm + ['/'] +' / '.join(runaway_front).split()
            doSomeFarm()
            farm = farm[:-l * 2]
    return "".join(farm)

def shut_the_gate(farm):
    # Identify regions
    start, regions = 0, []
    for i, c in enumerate(farm):
        if c == "|":
            if start != i:
                free = start == 0 and farm[0] != "|"
                regions.append([start, i, free, farm[start:i], False])
            start = i
    if start < len(farm) - 1:
        # Add final free region
        regions.append([start, i, True, farm[start:i + 1], False])

    # Link two extreme regions if both free
    if regions and regions[0][2] and regions[-1][2]:
        regions[0][-1] = True
        regions[-1][-1] = True

    # Convert to mutable structure and remove everthing that shouldn't be there
    f = [c for c in farm]
    for start, stop, free, s, linked in regions:
        s2 = "" if not linked else regions[0 if start > 0 else -1][3]
        # Identify potential loss conditions
        removals = set()
        if free:
            removals |= {"H", "C", "R"}
        if "H" in s + s2:
            removals |= {"A", "V"}
        if "R" in s + s2:
            removals |= {"V"}
        # Remove losses
        f[start:stop+1] = ['.' if c in removals else c for c in f[start:stop+1]]

    # Build resultant state
    return "".join(f)

import re

EAT = {'H': 'AV', 'R': 'V'}

def shut_the_gate(farm):
    parts = farm.split('|')
    partsSets = list(map(set, parts))
    for i in range(len(parts)):
        isOut   = i in [0, len(parts)-1]
        inThere = set('RHC') & (partsSets[i] | (partsSets[len(parts)-1-i] if isOut else set()))
        toErase = ''.join(EAT.get(x,'') for x in inThere) + 'HCR'*isOut
        if toErase: parts[i] = re.sub(r'[{}]'.format(toErase), '.', parts[i])
    return '|'.join(parts)

def shut_the_gate(farm):
    r = ''
    for i, c in enumerate(farm):
        left, right = farm[:i][::-1], farm[i+1:]
        if c in 'HCR':
            if '|' not in left or '|' not in right: c = '.'
        elif c in 'VA':
            for e in (left + farm[i+1:][::-1]).split('|')[0] + (right + farm[:i]).split('|')[0]:
                if e + c in 'HVHARV': c = '.'
        r += c
    return r

ANIMS = {'H': ['A', 'V'], 'R': ['V'], 'C': ['~']}

def shut_the_gate(farm):
    print(farm)
    f = list(farm)
    rng = list(range(0, len(f)))
    for i in rng:
        if f[i] in ANIMS:
            for food in ANIMS[f[i]]:
                j = 0
                idx = index_of(f, j, food)
                while idx is not None:
                    if idx < i and '|' not in f[idx:i]:
                        f[idx] = '.'
                    elif i < idx and '|' not in f[i:idx]:
                        f[idx] = '.'
                    elif '|' not in f[:i] and '|' not in f[idx:]:
                        f[idx] = '.'
                    elif '|' not in f[i:] and '|' not in f[:idx]:
                        f[idx] = '.'
                    j += 1
                    idx = index_of(f, j, food)

    for i in rng:
        if f[i] in ANIMS:
            if '|' not in f[i:] or '|' not in f[:i]:
                f[i] = '.'
    return ''.join(f)

def index_of(farm, j, food):
    try:
        return farm[j:].index(food) + j
    except:
        return None



shut_the_gate=lambda s:'|'.join(w.translate(
{ord(c):set(w)&set('RH'[i:]or'@')and'.'or c for i,c in enumerate('VARCH')}
)for w in '@'.join(3*[s]).split('|')).split('@')[1]

def shut_the_gate(farm):
    if not farm:
        return ""
    RA=[]
    if farm[0]!="|" and farm[-1]!="|"and "|" in farm:
        R = farm.rfind("|")
        L = farm.find("|")
        tmp = farm[R:]+farm[:L]
        if "H" in tmp:
            farm = farm[:R]+farm[R:].replace("A",".").replace("V",".")
            farm = farm[:L].replace("A",".").replace("V",".")+farm[L:]
        if "R" in tmp:
            farm = farm[:R]+farm[R:].replace("V",".")
            farm = farm[:L].replace("V",".")+farm[L:]
    res=''
    L = len(farm)
    T = [e for e in range(L) if farm[e]=="|"]
    if farm[0]!="|":        T = [0]+T
    if farm[-1]!="|":        T.append(L)
    idx=0
    while True:
        if T[idx]==T[-1]:            break
        S = T[idx]
        E = T[idx+1]
        tmp = farm[S:E+1]
        if "H" in tmp:
            tmp = tmp.replace("A",".").replace("V",".")
        if "R" in tmp:
            tmp = tmp.replace("V",".")
        if tmp.count("|")<=1:
            if "H" in RA:
                tmp = tmp.replace("A",".").replace("V",".")
            if "R" in RA:
                tmp = tmp.replace("V",".")
            if "H" in tmp:
                tmp = tmp.replace("H",".")
                RA.append("H")
            if "R" in tmp:
                tmp = tmp.replace("R",".")
                RA.append("R")
            tmp = tmp.replace("C",".")
        res+=tmp[:-1] if E!=T[-1] else tmp
        idx+=1
    return res

def eating(field):
    if "H" in field:
        field = field.replace("A", ".")
        field = field.replace("V", ".")
    if "R" in field:
        field = field.replace("V", ".")
    return field


def runing(field):
    field = field.replace("H", ".")
    field = field.replace("C", ".")
    field = field.replace("R", ".")
    return field


def shut_the_gate(farm):

    splited = farm.split("|")
    splited = [eating(item) for item in splited]

    if not farm.startswith("|") and not farm.endswith("|"):

        if "H" in splited[0] or "H" in splited[-1]:
            splited[0] = splited[0].replace("A", ".")
            splited[0] = splited[0].replace("V", ".")
            splited[-1] = splited[-1].replace("A", ".")
            splited[-1] = splited[-1].replace("V", ".")

        if "R" in splited[0] or "R" in splited[-1]:
            splited[0] = splited[0].replace("V", ".")
            splited[-1] = splited[-1].replace("V", ".")

    if not farm.startswith("|"):
        splited[0] = runing(splited[0])

    if not farm.endswith("|"):
        splited[-1] = runing(splited[-1])

    return "|".join(splited)

def shut_the_gate(farm):
    r=[]
    for g in farm.split('|'):
        if 'H' in g:
            g=g.replace('A','.').replace('V','.')
        elif 'R' in g:
            g=g.replace('V','.')
        r.append(g)
    if 'H' in r[-1]:
        r[0]=r[0].replace('A','.').replace('V','.')
    elif 'R' in r[-1]:
        r[0]=r[0].replace('V','.')
    if 'H' in r[0]:
        r[-1]=r[-1].replace('A','.').replace('V','.')
    elif 'R' in r[0]:
        r[-1]=r[-1].replace('V','.')
    r[0]=r[0].replace('H','.').replace('R','.').replace('C','.')
    r[-1]=r[-1].replace('H','.').replace('R','.').replace('C','.')
    return '|'.join(r)

import re

def shut_the_gate(farm):
  yards = farm.split('|')
  if len(yards) > 1:
    n = len(yards[0])
    yards[-1] += yards[0]
  for i, yard in enumerate(yards):
    s = ''
    if 'H' in yard: s = 'AV'
    elif 'R' in yard: s = 'V'
    if i == len(yards)-1: s += 'HCR'
    if s: yards[i] = re.sub('['+s+']', '.', yard)
  if len(yards) > 1 and n:
    yards[0] = yards[-1][-n:]
    yards[-1] = yards[-1][:-n]
  return '|'.join(yards)