# 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!

Source: codewars | Difficulty: EASY
Tags: String algorithms

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):
	(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:
		regions.append([start, i, True, farm[start:i + 1], False])
	if regions and regions[0][2] and regions[-1][2]:
		regions[0][-1] = True
		regions[-1][-1] = True
	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]
		removals = set()
		if free:
			removals |= {'H', 'C', 'R'}
		if 'H' in s + s2:
			removals |= {'A', 'V'}
		if 'R' in s + s2:
			removals |= {'V'}
		f[start:stop + 1] = ['.' if c in removals else c for c in f[start:stop + 1]]
	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('[{}]'.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)