Game Development Journal 11: Dealing Cards

One thing I find fulfilling and frustrating about game development is that there are a lot of things we do in real life without thinking too much about it that are somewhat tricky to represent in code.

One of the big challenges with machine learning is figuring out how to explain to a computer that the blob of data it has represents a pug. A person can look at a picture of a pug and know it’s some kind of smush-faced dog. They might mistake it for a bulldog or something similar, but they won’t look at it and say it’s a table.

The thing I am dealing with right now is dealing a hand in my card game. The cards are dealt into five different collections: Three player hands, the cards currently in play on the table, and the cards in the draw pile.

In real life, a deck is basically a mutable array. You deal the top four cards to the first player, then the same to the next two, then deal three more to each collection and what’s left turns into the draw pile.

Swift doesn’t really think that way. Swift likes immutability. The game has a certain amount of state. The players will play their cards until there are no more, which means that the array will by necessity have to be mutable so that the cards that have been played can be removed from the hand and moved to the player’s captured cards.

It’s possible to make this work, but it’s not super pretty. It’s fighting against the way Swift wants to work.

I really did not want to have to go through and assign each card individually in this function. Since it follows a pattern, where the players each get four cards, then the table gets three, then everything gets three, it seems like it should be automatable.

I have some concerns about how to approach this. This is my first attempt:

    func dealCards(shuffledDeck:[Card]) {

        // Deal four cards to the first player and each one after that
        players[currentPlayer].hand[0...3] = shuffledDeck[0...3]
        nextPlayer()
        players[currentPlayer].hand[0...3] = shuffledDeck[4...7]
        nextPlayer()
        players[currentPlayer].hand[0...3] = shuffledDeck[8...11]
        nextPlayer()
        
        // Deal three cards to the table
        cardsInPlay[0...2] = shuffledDeck[12...14]
        
        // Deal three  more cards to each player
        players[currentPlayer].hand[4...6] = shuffledDeck[15...17]
        nextPlayer()
        players[currentPlayer].hand[4...6] = shuffledDeck[18...20]
        nextPlayer()
        players[currentPlayer].hand[4...6] = shuffledDeck[21...23]
        nextPlayer()
        
        
        // deal three cards to the table
        cardsInPlay[3...5] = shuffledDeck[24...26]
        
        // put the rest in the draw pile
        drawPile[0...21] = shuffledDeck[27...47]
    }

Yes, I know. This is reeking of Code Smell. I have two blocks of code that are nearly identical except for the indices on the shuffled deck. This depends on me keeping track of where I am in my array of cards. It also depends upon me knowing how many cards are in my array.

This makes me deeply uncomfortable. I am not entirely certain how to set up conditional logic for this. If this was before, I would use nested For loops, but those seem to be going the way of the dinosaur.

I suspect this is a situation where map() would probably be the best approach, but I feel like it’s complicated to express. I have to keep track of how many elements are being added to each array and where I am at in the shuffled deck. I even just noticed that I put the wrong terminating index at the end of this method that I went back and changed. There are a lot of ways this can go wrong.

I want to leave this here for the time being and try to think through a better approach to this. I don’t want to add a bunch of functional garbage that is less clear and more complicated than what I have now. I know there are better ways to do this, but I also know there are a lot worse ways to do this.

I do not want to over engineer this. Nothing in this function is going to change. There will never be more than 48 cards in the deck. There will always be three players. I know a lot of the reason we don’t hard code stuff is to add flexibility for changing requirements. But I know these requirements won’t change.

Also, I feel comfortable when I read this method about what it is that it does. It follows the same logical structure that you would if you were actually dealing a deck of cards. I know as a programmer this looks terrible, but me as a person it feels logical because this is the process I would go through if I was actually dealing a hand of Godori.

Conclusions

I will probably refactor this based on input from other people.

I think a lot about human versus computer. I know as a programmer there are more efficient ways for me to do things than I have in this code in particular. But I am also a human being. I have my own biases of how I personally process information.

I have to maintain this code. If I look at this in a year not only do I clearly understand how it works, but I also have an understanding of the game logic about how the cards are to be dealt.

I am probably justifying myself too much, but I am really struggling with this. The reason we have the abstraction of programming languages instead of writing everything in assembly language or machine language is to make programming more human friendly. Does writing more verbose code that is more clear to me but breaks best programming practices make me a hack? Or are we making things harder than they have to be in the name of trying to be 10x programmers?

Only time will tell.