Keep getting invalid get index when shuffling Array

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By namathos

Hi,
I’m making a tarot card game and I’m coming across this error constantly:

Invalid get index '0' (on base: 'Array')

Basically heres what I’m doing, I have a deck of cards referenced from a JSON file in the form of a dictionary, I’m starting with a small sample but will be adding in the full deck later. Here’s an example of how an entry in the dictionary is set up:

[{
"ID" : "0",
"card" : "res://gfx/Clouds/Clouds01.png",
"title" : "Ace of Clouds",
"keyword" : "Opportunity",
} ]

My plan is to go through the deck, shuffle it then remove cards till I have just one card left which is added to a variable. It’s then assigned so the game can show it on screen.

var possible_cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

var deck = get_deck("Deck.json")
for drawn_cards in deck:
	possible_cards.shuffle()
	var drawn_card1 = deck[possible_cards[0]]
	possible_cards.pop_back()
	return drawn_card1

There’s a button on screen that when clicked reveals the next shuffle. The game is working fine, it’s shuffling the deck, taking out one card and assigning it but after a while it gives this error and crashes. I have three cards being shown on screen (drawn_card1, 2 and 3) they all have the same code different variables, the reason I did this was to avoid getting any duplicates. The clash seems to always happen with the 3rd card and on the 5th shuffle (5th time the button is pressed)

I’m rather new to programming so this is just going over me, any ideas what’s happening?

Some further information would be nice to solve it:

  • What parts of the third code snippet are inside a function? (most important)
  • Can you give the line the error occurs in? (would be helpful)
  • How long is your Deck.json array really? (could be a hint)

Btw:

  • If you don’t randomize() the game then that is the reason why it always happens the same moment.
  • Think you know it, but your json file is not a dictionary. It’s an array with (a) dictionary/ies inside. (Or at least what you showed is)

Hope I can help you soon!

Tip: Please add a godot3.1 tag next time because that’s an important information.

Jowan-Spooner | 2019-05-13 16:49

Thanks for the reply.

  • The code snippet is all in side a function, there are 3 total functions similar like this for each of the 3 cards to be shown. The variable possible_cards is pre assigned outside of the function
  • The error comes on the 3rd function draw_card_three(), specifically on the line var drawn_card3 = deck[possible_cards[0]]
  • There are at the moment 14 items in the deck, will be 78 later when all cards are added. The possible_cards was meant to act as a way to index them so I could extract the cards.

I didn’t know about the randomize() thing, I thought that was to be used when randi() is used. I do know it’s a series of dictionaries inside an array, does that change how it’s read?

Each card has a series of data associated with it so I figured the dictionary would make sense, but then I needed to fetch the right entries for the card selected so it’s been confusing.

namathos | 2019-05-14 11:15

I have another question: what is the loop for? The code will return instantly during the first run through, wont it? Is this the original indent of the return statement?

And is the possible_cards variable reassigned every time one of the functions is called or is it getting shorter every time? And which would be the way you want it: Should there be the possibility of picking one card twice?

What data type is the deck variable? Is it an array. What does the get_deck() function look like?

And yes, not doing randomize will lead to having the same result every time your game is code executed. That is pretty useful for debugging but probably not how you would like it in your final game :slight_smile:

I don’t think the Array/Dictionary thing is a problem, just something to make clear and keep in mind.

Sorry for asking many questions, but maybe it will help.

Jowan-Spooner | 2019-05-14 12:11

No worries, the more questions the better to understand :slight_smile:

  • The get_deck() function defines the json file and parses it. The variable deck is the data in the json file which is in the format above. It is an array with dictionaries inside it.
  • possible_cards is predefined above func _ready(): it shouldn’t be assigned every time since it’s supposed to reference the range of cards no?
  • The loop is for iterating through the whole deck of cards. At least that’s how I’m imagining it, for loops are a harder concept for me at the moment. I imagined it as the loop looks at a target in deck, shuffles the entries, assigns the first entry to drawn_card1 (or 2 or 3 depending on which function its in), then removes the cards at the end and returns the data
  • I don’t really get the same result every time though, every time I press the button the result is different, it’s just that on the 5th time I do it the game crashes at the code line with that error. So I don’t think randomize() would do any thing here.

What I understand is there’s either a:

  • Clash with the return statements, returning excess data if that’s a thing
  • Clash between the possible_cards data and the data returned though I don’t understand how
  • Or by the 5th time the button is pressed the data is removed entirely, again don’t understand how the loop is doing that

namathos | 2019-05-14 13:49

Sorry to say that, but I cannot reproduce this myself. The following code snippet works fine for me (the game crashes when I press the button the 15th time but that’s right). Maybe you can have a look at what is different in your script:

extends Control

var possible_cards = [0,1,2,3,4,5,6,7,8,9,10,11,12,13]
var deck = [{"Name":"Mycard1"},{"Name":"Mycard2"},{"Name":"Mycard3"},{"Name":"Mycard4"},{"Name":"Mycard5"},{"Name":"Mycard6"},{"Name":"Mycard7"},{"Name":"Mycard8"},{"Name":"Mycard9"},{"Name":"Mycard10"},{"Name":"Mycard11"},{"Name":"Mycard12"},{"Name":"Mycard13"},{"Name":"Mycard14"}]

func _ready():
	pass # Replace with function body.

func get_card1():
	for card in deck:
		possible_cards.shuffle()
		var card_1 = deck[possible_cards[0]]
		possible_cards.pop_back()
		return card_1

func press_button(): # connected to a button
	print(get_card1()["Name"])

I would say the loop statement does not make sense the way it’s used here, but it’s ok.

Could you have a look at the right side of the Debugger (when the error has happened) and tell if there are any hints like: The size of possible cardsis 0. Always a good way to find the problems is to print out some variables at some points like:

func get_card1():
    print(possible_cards)
    [...]


By the way the line

possible_cards.pop_back()

should probably be

possible_cards.pop_font()

Cause otherwise you can get doubles.

Jowan-Spooner | 2019-05-14 15:15

I had no idea what the info on the right side meant lol some of it is making sense I think what it’s doing is on the 5th press the array has no more entries inside it (i think)

Debugger

namathos | 2019-05-14 16:12

seems like. Any ideas what might cause this? Have you found differences between your and my code. Why has your deck a size of 28?

Jowan-Spooner | 2019-05-14 17:23

Hey you, I hope you will find a solution soon, but I will be off for the rest of the week so if you need my help it has to wait :slight_smile:

Jowan-Spooner | 2019-05-14 21:13

Hi, that’s fine :slight_smile: thanks for all the help. I ran your code independently and it worked fine with one card, but when I put it through 3 functions one for each card it gave the same result. I’ll poke at this some more see if I can get it done with less work arounds and possibly just the one function to handle all the cards so its 3 cards are fed to one array.

How would I call a value in a dictionary from a specific point? Because I’m thinking if I can get it in one array then I could say print title of entry number 2 in dictionary. Or would it be better to do that using multiple arrays?

It’s all a learning process for me. I’ll update this query with anything I come across :slight_smile:

namathos | 2019-05-15 10:31

I figured a way of simplifying it, not exactly a solution to the original problem and can’t say if it’s the most elegant of methods as I don’t really know what elegant code is rofl, but it is working. I ditched the for loop for something more relatable to me. Instead of fetching from a json file with the array/dictionary setup I’m referencing values from nodes that I’ve assigned custom values to and saving them to an array that makes them usable in the game. So I have an array with all titles, one with the card images to be shown on screen, another with keywords etc.

func get_cards():
  randomize()
    var cards = $Deck.get_child_count()
    # Assign random index values from deck
    var card1 = randi() % cards
    var card2 = randi() % cards
    var card3 = randi() % cards

    # Prepare Card01 by appending values to respective arrays
    title.append($Deck.get_child(card1).title)
    card.append($Deck.get_child(card1).card)
    keyword_up.append($Deck.get_child(card1).keyword_up)
    keyword_down.append($Deck.get_child(card1).keyword_down)

    # Prepare Card02
    if card2 != card1:
      title.append($Deck.get_child(card2).title)
      card.append($Deck.get_child(card2).card)
      keyword_up.append($Deck.get_child(card2).keyword_up)
      keyword_down.append($Deck.get_child(card2).keyword_down)
    else:	
      card2 = randi() % cards

    # Prepare Card03
    if card3 != card2 and card3 != card1:
      title.append($Deck.get_child(card3).title)
      card.append($Deck.get_child(card3).card)
      keyword_up.append($Deck.get_child(card3).keyword_up)
      keyword_down.append($Deck.get_child(card3).keyword_down)
    else:
      card3 = randi() % cards

I’ve made a function to check and reset those values which is checked when pressing the button so not letting each array go beyond 3 entries. I guess I could do this reset/check thing to the previous loop. All that for looping’s been giving me a headache lol, I’ll try again on that later but for now this is the solution I came up with.

namathos | 2019-05-15 13:31

Hi namathos, I would always say: “if it works, it works.” If you found a solution, then this is great. Well done!

This is not the the best code I’ve seen (mainly because it repeats many steps again and again → DRY) but it looks pretty good and most of it makes sense to me. Definitely way better then having three functions that are (nearly) exactly the same :-). You’r making progress! Good luck with your game

Jowan-Spooner | 2019-05-17 14:22