Blog

One AI Done… Mostly.

On my Ruby Uno clone called One…

Futuristic robot in virtual background

I've now completed the AI part of the project. There were some bits that were harder than others and some bits that were easier. I also managed to include the full functionality of the previous version so now you can play a pickup 2 over the top of another pickup 2 (same with pickup 4).

I think the hardest part of designing the AI was figuring out how to start. I wrote and rewrote pages of pseudo code and diagrams over and over. It wasn’t until I actually started coding properly that I had the ah-ha moment and figured out how to do it reasonably concisely. I’ve got 3 difficulty levels. The easy setting actively tries to lose, the medium setting is random and the hard setting actively tries to win. The middle difficulty was by far the easiest — randomly picking a card from the available options. One line of code and I was done.

Its kind of disheartening when I get the computer to play itself and the random one wins…

The hardest one was the hard setting. Sounds pretty obvious doesn’t it.

I wanted to assess the card to play based on a score of the final hand after that card was played but I realised that it was a lot simpler to give the cards a score and choose based on that rather than calculating a score for the entire hand.

The easy difficulty was easy once the hard was done because it just required copying, pasting and then changing one line of code from a greater than symbol to a less than symbol. I could have put in some more subtle additions to the AI decision making but I wasn’t even sure if it would make it that much better and it would have been a lot of coding for very little result.

So the guts of the AI card scoring for the hard setting I can't really show you but once all the possible cards are scored, the computer simply chooses the highest value and plays that.

There is a bunch more if statements than I wanted but in the end it was hard to avoid them.

Left to do: getting the computer to play itself automatically, a set number of times and record the percentages of wins for each level of difficulty. Might have to leave this for another day. Please download and enjoy the game as it is here:

One via Github

AI and the One

Neo from Matrix with green digital effect background

Just as Keanu was the One, so is my Ruby Uno program called One. The human player side is done, I’ve refactored the code into a more OOP style and brought back all the functionality of my original program. Now its time to have some real fun.

I’m dipping my toe into the matrix for the first time and creating an AI. Three actually.

I figure I can go about this AI two ways. The first by creating a bunch of ‘if’ statements such that - if you have the option of a matching colour or number, choose the colour etc etc. This is a perfectly feasible way of decision making. However, it‘s going to be hard to change and its not as cool as the second option, which I’m going to try.

The second option is to assign a numeric score to the cards and have the AI choose the card to play based on how many points it will have after playing the card. There will be base points each card will have plus additional points based on the whole hand. For instance, points will be awarded for having a card with the same number in another colour. If the AI has a choice of a red 5 and a red 7, and there is also a green 7 in the hand, it should choose the red 5 because it can switch colours from red to green with the 7 once the reds have run out (if the opponent draws a card). Theoretically, it should work. There is also another up side to this way of ‘thinking’. It’s easily tweaked. I can mess around with the values and see if I can get the AI to play ‘smarter’.

red eye Hal from 2001 a space odyssey

Eventually, I would like to add functionality to have the computer play itself in various levels of difficulty over and over and spit out a percentage of wins/losses at the end. This way I can really test the validity of certain strategies and card values.

So here’s what I’m thinking for the card scores and rules. The AI will try and get the lowest score it can each time it plays a card. This is the starting point for the hardest level of difficulty assuming 2 players:

Basic colour +70 (-1 for every matching number of another colour) Skip +50 (-1 for every other skip) Reverse +50 (-1 for every other reverse) Pickup2 +40 (+1 for every other PU2) Pickup4 +20 Wild +30 Hand rules: Every different colour in hand+20 If next opponent cards < 3=> Pickup 2 +100, Pickup 4 +100

Two exceptions to the score method will be:

  1. If opponent has 1 card remaining and they just played a wild (changing the colour), play a wild if you have one and change colour again.
  2. If you can only play a wild, and wild cards ≤ number of different colours in hand, draw a card.

The theory is with all these scores is that the computer will assess the score it will get after playing each card it is allowed to. Then choose the card resulting in the lowest score it will have after playing that card.

There will be three levels of difficulty. The scores above will be for the hardest. The easiest will be basically the opposite. The computer will actively try and lose. And the middle level will be choosing a random card.

Now to code it all. Wish me luck.

One Two Testing

Trying a video this time. Watch the video and then this makes a bit more sense.

Test Driven Development (TDD) is what we learned about this week and apparently its important.

Sounds crazy but you start with the test data and write the program after that. Well I didn’t know about it and started my program without test data. The good thing is though is that I haven’t finished writing the code and I haven’t actually started the implementation of the AI. So I can start the implementation of the AI with TDD in mind.

So here goes. Test data for the AI…

In my game of One (based on UNO) written in Ruby, there will be a significant difference between the strategy of an AI for a 2 player game as opposed to three or more players. The reason for this is two cards in the game are ‘skip’ and ‘reverse.’ Skip meaning skip the next players turn and reverse meaning reverse the order of play. In a two player game they both essentially mean whomever plays a skip or reverse gets another go. Not so in a 3 + player game. So the following test data is going to be for a two player game. I’m also going to concentrate on the ‘easy’ setting first. Start simple.

For those not familiar with UNO, the basic concept is the winner is the first person to lose all their cards. Players take it in turn to discard a card onto the discard pile but it has to match one of 4 colours or be the same number as the previous card.

So if you’re interested, here is just some sample hands and what the AI should play given its trying to lose at all costs (easy setting) (according to my best understanding of UNO strategy). I understand that this sample test data is way too small. It’s just an example.

Card decision order for easy setting, 2 players:

  1. Play wild pick up 4 or,
  2. Play wild card or,
  3. Play any pickup 2 or,
  4. Play any skip or,
  5. Play any reverse or,
  6. Play any matching number or,
  7. Play matching number of the colour you have the least of or,
  8. Play matching basic colour with matching number of another colour in hand or,
  9. Play matching basic colour with no matching number of another colour in hand or,
  10. Pick up card from pile (unable to play)
table showing test results

Legend:

First letter is colour (Red = r, Yellow = y, Blue = B, Green = g) wild = w

Second number is number of basic card or p =pickup 2, skip = s, or reverse = r

Wild pickup 4 is wp

I’m probably going to scrap this entire decision tree in favour of a points based system. Stay tuned for the next exciting episode.

One

A card game for my son.

Playing cards fanned out on a table

For the last few weeks, my son Marshall has really taken a shine to the card game Uno. We play as many games we can fit in before he goes to bed. This has meant that I have become somewhat of an expert (and so has he).

  1. It’s a fairly simple game as far as strategy goes and it got me thinking that it would make it a really good project to try and replicate in code. Obviously, it’s been done before. There are several examples of well executed Uno games available online but Marshall and I play our own rules slightly differently from the standard rules and we’ve now introduced a few custom cards as well. So why not replicate our version? Why not indeed.
  2. It will provide me a real world example where I can start to apply my new coding skills.
  3. I can make it more pretty down the line by giving it a snappy GUI.
  4. It’ll (hopefully) impress my son :-)
  5. If I call it “One” maybe I’ll avoid getting sued.

So here goes. My only problem here is finding the time to do it in-between classes, coding practice, assignments, looking after 2 kids, helping out the wife, keeping up the home, exercise, self care and the rest of life.

Sheesh.

I’ll keep you updated but here was where I started — an outline. Since blurting all this out, I’ve learned about classes and its morphed into another version already but this is my starting point…

ONE

Display rules function create deck create array of 108 cards called deck each containing a hash card {colour: red, number: 7} either [colour, number] or [colour, skip] [colour, rev] [colour, pickup_2] or special cards - [anycolour, null] or [anycolour, pickup_4] Determine number of players and make array turn_order [player_1, player_2, etc] create profiles — player_1_info = hash {type: human/computer, difficulty: easy} Difficulty? function Deal Cards Take cards (each hash out of the deck array and into the hands arrays (1 hand array eg player_1_hand for each player containing 7 random card hashes) example — player_1_hand = [{red, 7},{blue, 5}, {anycolour, null}, {yellow, pickup_2}, {red, 0} take random valid card from deck array and use it to start the discard array top_card_number = number from card chosen top_card_colour = colour from card chosen function Human interface show human their player_1_hand input from human — card to play ensure it follows turn logic function Turn logic if pickup_2 give 2 cards to next player in turn_order unless they have a pickup_2 also. if pickup_4 give 4 cards to next player in turn_order unless they have a pickup_4 also. only allow same colour or anycolour or same number/skip/reverse/pickup_2 add card to discard array delete card from hand array if current_player hand array is empty, current_player is the winner if skip played, move next player in turn_order array to end if rev, reverse turn_order array if anycolour, ask player to choose colour and assign to top_card_colour if current_player hand array has only one card left output “ONE!” function Computer strategy hard? try to play colour first, if more than one choice, choose the card with a number not repeated in the hand array, if has pickup_2, save till last card if no colour, play same number if no colour or number, play anycolour and change colour to the colour most prevelent in hand array

Skinning Cats and Coding Like Elsa

Firstly, don’t get me wrong, we have a cat, I love cats. She’s old and she throws up every second day but I would never hurt her. I’ve seen what the internet does to people who #$%* with cats…

Cat looking down from above

I am of course referring to the expression “There’s more than one way to skin a cat.” And we’re talking about Ruby code here. You could even Rubify it (if that’s a word) — “There’s more than one way to cut a Ruby.” It could also apply to other languages too… “There’s more than one way to catch a Python.” or “There’s more than one way to brew Java.” or even “There’s more than one way to swim in the C++…” I can hear the groans but hey, I’m a Dad. I’m allowed. But especially in Ruby, there’s more than one way to do things.

But I hear you saying that’s all well and good but what has it got to do with Elsa? Well in the movie Frozen…

— -SPOILER ALERT — -

Anna has her heart frozen accidentally by her sister Elsa. Then we learn from a troll that “Love will thaw a frozen heart.” We are then led to believe (from the romantic story arc of Anna and Kristoff) that Kristoff will come to the rescue and save Anna by kissing her. But no — there’s a plot twist and Anna ends up sacrificing herself to save Elsa’s life. Her act; motivated by the love of her sister thawed her own frozen heart. Cool. There’s more than one way to thaw a frozen heart. You go girl.

— -SPOILER ALERT — -

When I looked back at my day last night, I got behind in my coding and I asked myself why? The answer was ,that I got caught up with a bit of code that I wanted to write a particular way. And I didn’t let it go. I was like a dog with a bone. A toddler with a square peg, desperately trying to jam the thing into a round hole. I’ll just try running it again and see if it works now. Now that I’ve stared at it for 5 minutes. Surely, now, it will work. The definition of insanity is to do the same thing and expect different results. I was insane.

I needed to take a coding lesson from Elsa… Let it go. Let it go. There’s more than one way to skin a cat. Ruby is a very versatile language. Find another way. It may not be the way you envisioned, but it will work. Move on. Because let’s be honest folks, when is time not a factor?

Now, I’m sure there is some value in keeping at it. Persistence. Determination. You will be learning stuff regardless. But mostly you’ll be learning a lesson in frustration. There’s a fine line between giving something a decent go and having 40 tabs open on the same subject an hour later. It’s a balancing act for sure.

Making the leap

Laptop with ubuntu logo on the screen

After my first week of coder academy, I was introduced to the command line. Pretty cool stuff but it doesn’t come naturally to Windows.

The good people at my Coder Academy course suggested running a virtual machine to run Linux. Sounds like a reasonable idea. However while attempting to install Ubuntu onto my laptop, on a virtual box, I ran into some problems. The keyboard refused to work half way into the install. After trawling the internet for solutions, I came across a few people with the same issues. Unfortunately none of the solutions seemed to be getting me anywhere. But then I thought outside the box… what do I do with windows on this laptop, that I wouldn’t be able to do with Linux? Why do I need Windows at all?

This is going to be my developer computer. I’m not going to play any games on it. I’ve got my desktop computer anyway… what can’t I do on Linux?

Nothing.

I. Don’t. Need. Windows.

The realisation was very satisfying. So that’s it. I’m giving Windows the flick. Googling issues that people have had installing Ubuntu on my Lenovo Z570 came up with a couple of issues with the wifi and graphics card driver but we’ll see if they rear their ugly heads. I’m doing this.

Ok. Skip ahead an hour or so and here we are. No issues. Works perfectly. Love the Gnome GUI but I’m looking forward to familiarising myself with the terminal interface even more. I think I’m now officially a Linux/Ubuntu fanboi. That didn’t take long did it?

Bye Windows. You won’t be missed.

My Coding Journey Starts Here


I keep thinking back to ‘Monty Python’s and Holy Grail’ and the line “I’m 37, I’m not old!”

Headshot Jason Stacy

Well I’m 47 but I still think that I’m not old. My young children may disagree but I don’t care. And this is why I’ve decided to start a new career as a Web Developer.

It all started when I was talking to a friend who is a developer, he mentioned that they had hired some people straight out of some coding boot-camps… Interesting.

Maybe I could do this? After all, I’m not a stranger to coding. I’ve done a couple of websites and learned some stuff online. I started investigating boot-camps and I liked the look of Coder Academy.

The thing that stood out for me and ended up tipping the scales was the fact that the course was accredited. At the end of it, I would have a diploma in IT if nothing else. My journey was taking shape.

After applying, I found out they have a diversity scholarship. Me having one leg and all, I thought why not give it a go right? And what do you know? I got it! My journey started with a Sherpa!

Unfortunately, Covid 19 reared its ugly head and a course that was meant to be face to face suddenly turned online.

Kudos to the Coder Academy team though. Hey, If anyone can transform a course to an online experience in less than a week it’s going to be them.

Unfortunately, my back has given out again and I’m trying to learn while horizontal. It’s not ideal but hopefully things will improve shortly.

Jason in bed with computer on stable table

So here I am, just finished the first week and have an inkling of Command Line and a smidge of Ruby but am super excited and have a thirst for more. Stay tuned.