0

I'm making a snake game, and for my collision detection, I have an if statement checking if the list of lists that contains coordinates of each square contains identical coordinates. If it finds a duplicate, the snake has overlapped itself.

The way I tried to check this is with the following:

if len(test_data) >= 2:
            print('snake is',len(test_data))
            if len(test_data) != len(set(test_data)):
                print('within oneself')

I get the following:

[[300, 120], [300, 100], [300, 80], [300, 60], [300, 40], [300, 60], [300, 80], [300, 100], [300, 120], [300, 140]]

---
if len(test_data) != len(set(test_data)):
TypeError: unhashable type: 'list'

I've seen this work with ordinary values in a list however, my game uses lists. Furthermore, if this works with tuples, I can't convert to tuples in a list as my whole program is centered around the list in lists. I've seen some solutions like using in but I don't understand that in python yet. Any help would be appreciated.

if len(test_data) >= 2:
            no_head = test_data
            no_head.pop(length-1)
            n=0
            for x in range(len(no_head)):
                if test_data[length-1] == no_head[n]:
                    print('within oneself')
                else:
                    pass
                n += 1

this is another way I did it, where it checks if the head of the snake (last item in the list) is equal to an item of the list, then it cycles through the list checking. but it didn't work

  • Since only the head of the snake can move, isn't it sufficient to test ``test_data[-1] in test_data[:-1]``? Note that "list in list" seems unsuitable for this game – a "tuple in deque" would be more appropriate. What problem do you have swapping the inner lists for tuples at least? – MisterMiyagi May 21 '21 at 12:34
  • I have to update all the lists constantly because of course the snake is moving. Preferably I would want to stay with nested lists. I tried what you did mentioned, but it literally magically broke my code even though it doesn't interfere with anything. – throwaway123pie May 21 '21 at 12:36
  • Wait, you are updating every single nested list when the snake moves? Why not just append the next position and left-pop the last position? – MisterMiyagi May 21 '21 at 12:40
  • `set` requires hashable variable types as content items. Lists are not hashable, hence you can't use lists as items in a set. – 9769953 May 21 '21 at 12:40
  • 1
    If you *insist* working with lists of lists, then convert it to a list of tuples just for the set check. `set(map(tuple, set_data))`. – Reti43 May 21 '21 at 13:03

3 Answers3

1

Like a comment said, sets need hashable values. Similar questions asked here, probably where you got the code in the first place.

Either

  1. Program a new way to check for duplicates. ( Time needed will rise exponentially, O(n^2), bad way.
  2. Make your Coordinate Lists (i.e. [4,5] etc.) to tuples. Use (4,5) instead of [4,5]. And use your method.
  3. Check for duplicates the moment you input an item, and check with methods like List.indexOf().
dbice
  • 76
  • 3
0

I think the itertool solution is good.

But, even if you do not want to use tuples, may be you could just use them in the 'set()' method ?

Something like this :

if len(test_data) != len(set(map(lambda x : tuple(x), test_data))):

I did some small test and it seems to work.

Paul Zakharov
  • 515
  • 2
  • 15
  • 2
    The lambda is superfluous. This can be shortened to `map(tuple, test_data)`. – Reti43 May 21 '21 at 13:03
  • I agree. I have some wrong habit to always use "lambda" in map. Probably because it's necessary, but you are right in this case we could do it much simple as you explain. Thanks for correction. – Paul Zakharov May 21 '21 at 13:11
-1

import library itertools from python to remove dublicate:

import itertools    
if len(test_data) >= 2:
            print('snake is',len(test_data))
             test_data.sort()
             filter_data = [li for li,_ in itertools.groupby(test_data)]
            if len(test_data) != len(filter_data):
                print('within oneself')

this will do your work

harsh
  • 1
  • 1
  • 1
    Sorting the list inplace seems like a bad idea. It seems that the head of the snake is always at the end of the list and that will affect it. – Reti43 May 21 '21 at 13:00