Skip to main content

AI Coding Experiment

Freecell Card Game

CursorReactTailwind CSS
Play the Game

Back Story

This project started in 2024, before AI coding assistants became wide-spread. I started playing Freecell in my spare time, and realized that coding a version of the game would be the perfect technical and logical challenge for me.

I started designing it step-by-step, I built a full-stack web application from scratch (PostGreSQL/Django/GraphQL/React). I meticulously designed all the database models myself, and got to the point (after 2 days) where I was able to call a GraphQL mutation to create a new game.

At this point, I became absorbed with work, and the project was put on hold. Fast-forward to 2026, I decided to finally finish the game. At this point, Cursor had taken over the dev community, and building applications from scratch was simply the slow way to work.

I was skeptical of Cursor at the time, so I decided to let it build the project for me and see for myself what all the hype was about.

Coding with AI

Since I had already started building the game before, I knew the general logic that was required to create and set up a Freecell game. I decided to build it on the frontend only (no database). I started by giving Cursor small, well-defined tasks. I checked the generated code thoroughly and weighed it against what I would have done. The majority of the time, it passed my expectations.

In one hour, it had generated all the code necessary to create a deck of cards, shuffle them, organize them into 8 piles, and display the cards on the tableau. The code was clean, strongly-typed, and well-documented. I had to give it a few screenshots to adjust the positioning of the cards, but otherwise, it performed extremely well.

When it came to code the interaction, I started to notice a few quirks. It was having trouble calculating the logic behind whether a card or sequence of cards could be placed on a tableau pile. After Cursor tried and failed several times, I stepped in and looked closer at what it was doing. The code had gotten very messy, and after reading it I saw that it was making some very incorrect logical errors. The system that it had built was flawed, and instead of stepping back and evaluating the system, it tried to fix individual bugs one on top of the other. In each iteration, it added more code, causing more confusion and more bugs. I finally had to step in and write the logic myself. After I gave it a nudge in the right direction, however, it knew exactly what to do.

Ultimately, this whole experience made me glad that I entered the tech industry before the emergence of AI. That I was humbled through countless hours on Stack Overflow, reading technical documentation word-for-word, breaking and rebuilding code, and hunting down miniscule bugs late into the night. That experience strengthened my ability to solve problems creatively, to respect the code that I write, and to instinctively recognize bad patterns, which is a crucial skill for any developer trying to leverage AI.

Takeaways

  1. 1. Design the system in your head first.

    It is so easy to sit back and give AI autonomy. More often than not, it will find a way to make your project work, no matter what kind of coding sacrilege it has to commit. If you are not following along with what it's doing, you may end up with a working application, but the code will be an absolute abomination. Ultimately, this will cause more trouble in the long run.
    Make sure you know the implementation plan. Use AI to brainstorm if necessary, but when it comes to actual coding, you control the process.

  2. 2. When it comes to important logic, give it small, incremental tasks.

    I have found by trial and error that in order to prevent AI from coding off the rails, it needs step-by-step instructions. There are some tasks that are simply too large for it to handle, and there are some layers of abstraction that seem to be unreachable for it at this point in time.
    Come up with a rough plan in your head, and then give it small, incremental tasks to achieve that goal. I have found that it works exceptionally well when used in this way.

  3. 3. Ask it to audit your code.

    This approach can be extremely useful when you want to find logical or performance-related bugs hiding in your code. You don't know what you don't know, but lucky for us, AI knows everything about everything. Giving it such a simple and well-defined task can open your eyes to coding patterns you never knew existed, old habits that you didn't realize were problematic, or just simple human-errors that you have overlooked.
    Ask it for suggestions, then do your research on what it gives back. This is a great way to ensure that you, as a developer, continue to grow.

  4. 4. Use rules.

    When given a page or a component to build, AI will play fast and loose with custom colours, styles, and interaction patterns. So many times I have had to manually remove a pattern that creates inconsistency in the codebase. This can be solved by creating simple rules: Always stick to the design tokens. Never use custom styles. Use wrapper components instead of base components. Don't override typography sizes. These kinds of things will save you a lot of time and effort.
    Come up with a set of foundational rules, and stick to them.

  5. 5. Don't stop learning.

    All together now: "AI is a powerful tool, but it is not a replacement for human intelligence". The knee-jerk reaction of asking AI to solve all your bugs is a slippery slope to becoming a passive developer. You need to be able to think critically and creatively to even use it effectively. You need to be able to understand the code you are writing, and the code you are reading. You need to be able to understand the problems you are solving, and why you are solving them.
    Read documentation, take courses, practice new skills. Ask AI to explain things to you. Learn new technologies. Grow as a developer, and a person.

← Back to projects