The title is a more optimistic variation on the KISS principle, also related to YAGNI. Faithful readers of this blog may recall a recent posting wherein I clearly failed to heed these two principles. I should have gone for the most straightforward solution, being willing to rework later only if needed.
I spent most of today battling a minimax algorithm for a tic-tac-toe AI. I ended up questioning whether the logic that determined the winner of a grid was working correctly, so I ripped out all of the fancy grid-scanning logic I put in last time and replaced it with the following very simple code:
(defn winner? [grid mark]
(or (and (= (grid 0) mark) (= (grid 1) mark) (= (grid 2) mark)) ; row 1
(and (= (grid 3) mark) (= (grid 4) mark) (= (grid 5) mark)) ; row 2
(and (= (grid 6) mark) (= (grid 7) mark) (= (grid 8) mark)) ; row 3
(and (= (grid 0) mark) (= (grid 3) mark) (= (grid 6) mark)) ; col 1
(and (= (grid 1) mark) (= (grid 4) mark) (= (grid 7) mark)) ; col 2
(and (= (grid 2) mark) (= (grid 5) mark) (= (grid 8) mark)) ; col 3
(and (= (grid 0) mark) (= (grid 4) mark) (= (grid 8) mark)) ; diag 1
(and (= (grid 2) mark) (= (grid 4) mark) (= (grid 6) mark)))) ; diag 2
(defn winner [grid]
(cond (winner? grid X) X
(winner? grid O) O
:else nil))
This code is not flashy. It almost screams, "REWORK ME!" (and I will), but it works, and it also runs much faster than the previous grid-scanning implementation, which made certain testing scanarios more feasable.
Depending on what features are needed in the future, it's likely that this code will get a rework, but maybe not...