The Hunger Games - Zoo Disaster!

20181106_Codewars_5kyu_who_eats_who

Posted by Huiyang_Lu on November 6, 2018

The Hunger Games - Zoo Disaster!

Codewars Kata 46√

Description

https://www.codewars.com/kata/5902bc7aba39542b4a00003d/solutions/python
-简述:本题假设存在一个动物园,里面有多种的动物和植物(种类给定),根据给定的食物链规则,求出动物园里最后剩下哪种动物。
-思路:将食物链规则变为列表形式,检测动物园里的动物列表中任意相邻两个动物的组合是否为食物链规则列表中的一项,若是,则删掉被吃掉的那个动物,循环至最后输出剩下的动物。
-难点:1 如何分类讨论 2 如何防止time out

Story A freak power outage at the zoo has caused all of the electric cage doors to malfunction and swing open…

All the animals are out and some of them are eating each other!

It’s a Zoo Disaster!
Here is a list of zoo animals, and what they can eat

antelope eats grass
big-fish eats little-fish
bug eats leaves
bear eats big-fish
bear eats bug
bear eats chicken
bear eats cow
bear eats leaves
bear eats sheep
chicken eats bug
cow eats grass
fox eats chicken
fox eats sheep
giraffe eats leaves
lion eats antelope
lion eats cow
panda eats leaves
sheep eats grass

Kata Task

INPUT
A comma-separated string representing all the things at the zoo

TASK
Figure out who eats who until no more eating is possible.

OUTPUT
A list of strings (refer to the example below) where:

The first element is the initial zoo (same as INPUT) The last element is a comma-separated string of what the zoo looks like when all the eating has finished All other elements (2nd to last-1) are of the form X eats Y describing what happened

Notes
Animals can only eat things beside them

Animals always eat to their LEFT before eating to their RIGHT

Always the LEFTMOST animal capable of eating will eat before any others

Any other things you may find at the zoo (which are not listed above) do not eat anything and are not edible

Example

INPUT
“fox,bug,chicken,grass,sheep”
1 fox can’t eat bug
“fox,bug,chicken,grass,sheep”
2 bug can’t eat anything
“fox,bug,chicken,grass,sheep”
3 chicken eats bug
“fox,chicken,grass,sheep”
4 fox eats chicken
“fox,grass,sheep”
5 fox can’t eat grass
“fox,grass,sheep”
6 grass can’t eat anything
“fox,grass,sheep”
7 sheep eats grass
“fox,sheep”
8 fox eats sheep
“fox”

OUTPUT
[“fox,bug,chicken,grass,sheep”, “chicken eats bug”, “fox eats chicken”, “sheep eats grass”, “fox eats sheep”, “fox”]

My solution
def who_eats_who(zoo):
    a = [['grass','antelope'],
    ['little-fish', 'big-fish'],
    ['leaves','bug'],
    ['big-fish', 'bear'],
    ['bug', 'bear'],
    ['chicken','bear'],
    ['cow','bear'],
    ['leaves','bear'],
    ['sheep','bear'],
    ['bug','chicken'],
    ['grass', 'cow'],
    ['chicken', 'fox'],
    ['sheep','fox'],
    ['leaves','giraffe'],
    ['antelope','lion'],
    ['cow', 'lion'],
    ['leaves','panda'],
    ['grass','sheep']]
    init = zoo.split(',')
    rst = []
    j = 0
    while j<len(init):
        if j > 0 and [init[j-1],init[j]] in a:
            rst.append(init[j]+' eats '+init[j-1])
            init.pop(j-1) # 不可以用remove,因为remove删除的是第一个该字符,pop对应索引
            j = 0
        elif j<len(init)-1 and [init[j+1],init[j]] in a:
            rst.append(init[j] + ' eats ' + init[j + 1])
            init.pop(j+1)
            j = 0
        else:
            j+=1
    return [zoo]+rst + [",".join(init)]

print(who_eats_who('cow,cow,sheep,bug,cow,busker,grass,little-fish,lion,sheep,fox'))

ps: 一开始用了几个for循环,果不其然超时了…有想过用dict,不太会写,直接用while+判断也还可以。pop和remove的区别要注意,一开始用remove一直报错,原来是random test里面字符有重复出现的,所以不能用remove.

Given solutions
EATERS = {"antelope": {"grass"},
          "big-fish": {"little-fish"},
          "bug":      {"leaves"},
          "bear":     {"big-fish", "bug", "chicken", "cow", "leaves", "sheep"},
          "chicken":  {"bug"},
          "cow":      {"grass"},
          "fox":      {"chicken", "sheep"},
          "giraffe":  {"leaves"},
          "lion":     {"antelope", "cow"},
          "panda":    {"leaves"},
          "sheep":    {"grass"}}

def who_eats_who(zoo):
    
    ansLst, zooLst, n = [zoo], zoo.split(","), 0
    
    while n < len(zooLst):
        while n > 0 and zooLst[n-1] in EATERS.get(zooLst[n], set()):                            # Eats on its left
            ansLst.append("{} eats {}".format(zooLst[n], zooLst.pop(n-1)))
            n -= 2
        
        while n >= 0 and n != len(zooLst)-1 and zooLst[n+1] in EATERS.get(zooLst[n], set()):    # Eats on its right
            ansLst.append("{} eats {}".format(zooLst[n], zooLst.pop(n+1)))
        
        n += 1     # Nothing to eat, step forward
        
    return ansLst + [','.join(zooLst)]

zoo_relations = {
"antelope": ["grass"],
"big-fish": ["little-fish"],
"bug": ["leaves"],
"bear": ["big-fish", "bug", "chicken", "cow", "leaves", "sheep"],
"chicken": ["bug"],
"cow": ["grass"],
"fox": ["chicken", "sheep"],
"giraffe": ["leaves"],
"lion": ["antelope", "cow"],
"panda": ["leaves"],
"sheep": ["grass"],
}

def who_eats_who(zoo):
    animals = zoo.split(",")
    idx = 0
    res = [zoo]
    
    while True:
        if len(animals) == 1 or idx >= len(animals):
            res.append(",".join(animals))
            break

        if idx-1 >= 0 and animals[idx-1] in zoo_relations.get(animals[idx], []):
            res.append("{} eats {}".format(animals[idx], animals[idx-1]))
            del animals[idx-1]
            idx = 0
        elif idx+1 < len(animals) and animals[idx+1] in zoo_relations.get(animals[idx], []):
            res.append("{} eats {}".format(animals[idx], animals[idx+1]))
            del animals[idx+1]
            idx = 0
        else:
            idx += 1

    return res
Points

1 从列表中删除被吃掉的动物时,不可以用remove,因为remove删除的是第一个该字符,pop对应索引


Related Issues not found

Please contact @huiyanglu to initialize the comment