Tag Archives: ios

Tic Tac Toe in Swift with a UICollectionView

I’m starting to ramp up how much work I put into using Swift to eventually switch over to using it completely over Objective-C now that Apple has released version 1.0 with iOS 8.

One of my first projects was to make a simple Tic Tac Toe game in Swift. What started out as something relatively simple, as Tic Tac Toe isn’t the most complex game, turned into something much more involved.

Utilizing standard UIKit components and implementing a MinMax algorithm to make the AI unbeatable, I set out to make a barebones, but fully functional, game of Tic Tac Toe in Swift.

Without going into too much nitty gritty detail here on my website, I’d implore you to just browse through the source code over on GitHub. I’ll lay out some of the more important parts which I enjoyed making.

UICollectionView as the Tic Tac Toe Board

Instead of manually laying out 9 buttons or interaction enabled views, I instead went with what could be considered overkill and created the board using a 3×3 grid UICollectionView. I chose to do this for several reasons:

  1. Subclassing the UICollectionViewFlowLayout is neither difficult nor scary and getting familiar with the UICollectionViewLayout protocol is pretty important
  2. The UICollectionViewFlowLayout allows you to make a grid with even spacing pretty darn easily and pretty much straight out of the box. Just make sure you have 3 sections with 3 rows each.
  3. Built in item selecting meant I could hook that into my board pretty easily:
    func collectionView(collectionView: UICollectionView!, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        if manager.placedPiece(indexPath.row, y: indexPath.section) {
            setPlayersLabel()
        }
    }
  4. Automatically scales any any resolutions to work on both the iPhone and iPad as well as easy to customize just like any other standard UIKit control.

Keeping all Tic Tac Toe logic in the GameManager

This meant all of my display logic was handled in my UIViewController and any sort of item placing was handled in the GameManager class. One particular good example was the item placing that I showed above in #3. The if manager.placedPiece(indexPath.row, y: indexPath.section attempts to place a piece at the provided indexPath coordinates for the current player. If it’s successful it’ll return true and tell the UIViewController to change its display of whose current turn it is.

This way the UIViewController doesn’t really ever need to tell the GameManager what to do; however, the GameManager can notify the UIViewController when it should update something accordingly, like in the actual placedPiece method:

func placedPiece(x : Int, y : Int) -> Bool {
    let piece = board.pieceAt(x, y: y)
    if piece.isOpen {
        if whoseTurnIsIt == 1 {
            piece?.playerOwner = player1
        }
        else {
            piece?.playerOwner = player2
        }
        viewController.collectionView.reloadItemsAtIndexPaths([NSIndexPath(forRow: x, inSection: y)])
        nextTurn()
        return true
    }
    
    return false
}

The code is pretty readable, but the last part where we reload the UICollectionView’s cell at the location given means we update the UI to display the newly placed piece if need be, instead of just reloadData-ing the entire UICollectionView. Sure – performance wise a 3×3 grid isn’t going to kill anything but this is a matter of principles, right?

The Unbeatable AI

This was a requirement that I seriously didn’t think would take that long but ended up being a lot more involved than I thought. I started out by doing my best to handle all of the cases by hand. I was able to make the AI unbeatable EXCEPT for cases when I, the user, would create “Forks” (Turns where in the next turn I’d have two ways to possibly win). Here’s the logic for the AI’s turn:

  1. Check if the middle piece is open. If it is, place it, otherwise choose a corner and place it only if it’s the AI’s first turn.
  2. Check if the AI has two pieces in a row and can place a third, and if so place it there to win (horizontal, vertical and diagonal)
  3. Check if the player has two pieces in a row and can place a third, and if so place it there to block the player from winning (horizontal, vertical and diagonal)
  4. Check for a fork – This was what I was missing and will explain in a bit
  5. Place it in the center if it’s open
  6. Place it in any free corner
  7. Place it in any free side piece

For the longest time, I couldn’t figure out how to do #4. Searching Google suggested I create a MinMax algorithm for the AI to determine which move gives it the best chances to win. I fortunately found an example of how to do this in Java, to which I then converted over to Swift.

MinMax in Swift

I’m not going to try to reexplain how the MinMax algorithm works in this instance as the link provided will do a much better job at it; however, if the score that it returned to my when checking for any forks the AI should make met a positive score, the AI would place an item there. This made the AI unbeatable!

unbeatable tic tac toe AI

Wrapping up

In the end, I was pretty happy with how this turned out! Now, if I was a good developer I’d go ahead and write some tests to make sure my logic was sound… but we can save that for another day.

 

UIViewController and UITableView in Swift

I originally wrote this post back when Swift 1.0 came out. Since then Apple has released several new version of Swift with new syntax. I’ve updated this post accordingly – Bay 11/13/2015

I’m just starting to play around with the newly announced programming language, Swift.

So far it’s a bit tricky to get used to the new syntax simply because when I first started writing Objective-C I had to learn some of its funky behaviors and nuances. Swift reverses a lot of those decisions and brings it inline with more modern languages.

To get started with Swift, aside from playing around in a Playground with it, I’ve decided to just start rewriting basic controls that I’m familiar with in Objective-C. To start, I rewrote what is a super basic UIViewController with a UITableView as a subview, displaying its contents.

(all code snippets are in Swift, don’t mind them being labeled as Objective-C)

class DumbTableViewController: UIViewController, UITableViewDataSource {
}

Let’s declare our data source.

var items: [Int] = [Int]()

Next we implement the viewDidLoad method that we’re so familiar with but this time we’re “overriding” it.

    override func viewDidLoad()  {
        super.viewDidLoad()
        
        self.view.backgroundColor = UIColor.whiteColor()
        
        // Loop through 0 and 100 (including 100)
        // and append it to our datasource
        (0...100).map({ items += value })
        
        // Create our UITableView with our view's frame
        var tableView: UITableView = UITableView(frame: self.view.frame)

        // Register our cell's class for cell reuse
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")

        // Set our source and add the tableview to the view
        tableView.dataSource = self
        self.view.addSubview(tableView)
    }

Implement the two required methods in the UITableViewDataSource protocol:

    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

 

    func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
        // dequeue a cell for the given indexPath
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        
        // set the cell's text with the new string formatting
        cell.textLabel.text = "\(items[indexPath.row])"
        
        return cell
    }

And that’s it! Now we have a UITableView displaying 0 – 100. Not that useful, but it allows us to start seeing what was familiar with Objective-C in a new light.

The full code source can be found at this Gist.

Handling Bad Connectivity with AFNetworking 2

I’ve been a web developer for the past ten years. There’ve always been plenty of challenges for me while creating websites – some I’ve handled better than others. I’ve run into file submission security issues, handling vast amounts of downloads, terrible web designs, hardening servers and more. There’s one thing I never had to contemplate until I started developing mobile applications: bad connectivity issues.

With DohGames, if a user ever had an issue connecting to the site or the download, I could just chalk it up to an internet issue or some faulty setting on their router (AKA, not my concern). The vast majority of the time though, a user’s connection would be reliable enough and out of my realm of control. A simple refresh to the page, or the clicking of the button again would fix the problem.

With mobile apps, it’s a different story.

Bad Connectivity Issues Abound

Your users are out and about. They could be traveling in a car, underground, in the middle of nowheresville USA or in a super crowded city with millions of users all fighting for their connections. Connections will be dropped or a lot slower than they should be in 2014. It sucks but you have to handle it unless you want a poorly rated application.

While I don’t feel like I could sufficiently discuss the various design decisions on how to handle this all (I’m a developer, not a designer for good reason), I did run across this while working and had to implement what we felt would work best for our app.

AFNetworking to the Rescue

afnetworking-logo bad connectivity tutorial

I recently upgraded our networking code to utilize AFNetworking 2. We were previously using a completely handmade solution that was unreliable, clunky and full of boilerplate code that had to be copy and pasted every time you wanted to add a new request. It sucked.

A lot.

I could write plenty about AFNetworking (and hopefully will) so I’ll leave out all of the details BUT one of the added features of it, that I was completely unaware of at the time of making the switch, was the built in ability to handle bad connectivity issues with the AFNetworkReachabilityManager.

Every AFHttpRequestOperationManager has a ReachabilityManager associated with it. This ReachabilityManager then has a block called reachabilityStatusChangeBlock that is called whenever your device loses/gains connectivity. We can utilize this to our advantage!

The reachabilityStatusChangeBlock is called with a AFNetworkReachabilityStatus parameter which tells you’re the current state of your connection. Using this, we can tell our app to do whatever we want.

For example, inside your subclassed AFHttpRequestOperationManager (I do this inside my -(id)init), you can specify your block as follows:

[self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status){
	switch (status) {
		case AFNetworkReachabilityStatusUnknown:
		case AFNetworkReachabilityStatusReachableViaWiFi:
		case AFNetworkReachabilityStatusReachableViaWWAN:
			// Our connection is fine
			// Resume our requests or do nothing
		break;
		case AFNetworkReachabilityStatusNotReachable:
			// We have no active connection - disable all requests and don’t let the user do anything
		break;
		default:
			// If we get here, we’re most likely timing out
		break;
	}
}];

// Set the reachabilityManager to actively wait for these events
[self.reachabilityManager startMonitoring];

AFNetworking (and I) would suggest you resume ([self.operationQueue setSuspended:NO]) the operationQueue on your AFHttpRequestOperationManager when your connection is OK or suspend it ([self.operationQueue setSuspended:YES]) when these events occur so that when the connection is fixed, any actions the user wanted to take will resume normally.

You can test this out once you’ve added it to your AFHttpRequestOperationManager by running your application, setting a breakpoint inside of that block, and toggling the AirplaneMode on your device/simulator.

What else?

That’s pretty useful in itself; however, there’s still a lot more to be accomplished with this code block! Notice how my final case in that switch statement mentions timeouts? What if the user just had a bad connection but is fine now? What if their connection is fine but your backend is running slowly? Do you reattempt? Do you completely disable the app? Let the user continue with no notification whatsoever?

This is where things can get tricky.  Let’s just say it involves implementing an attempt count as well as the ability to easily retry requests. But that’s for another day and article.