I whipped this up last night and was wondering if anyone had any thoughts/comments on it; for example, on:Code organisationCoding styleOther improvementsSemantic errors(ns tictactoe.core)(comment   Author: Liam Goodacre  Date:   03/06/12  This module allows the creation and progression of tictactoe games.  To create a game, use the make-game function:  (make-game)  A game is a map with the following data:    :play-state     :playing | :player1 | :player2 | :draw    :level-state    [:player1|:player2|nil]    :scores         {:player1 Int, :player2 Int, :draw Int}    :turn           :player1 | :player2 | :none  If the game isn't over, play-state is :playing.  If play-state is :player1 or :player2, this indicates that that player won.  If play-state is :draw, then the game completed with no winner.  level-state is a vector or nine elements.  An empty cell has the value of nil.  If a player uses a cell, then the cell has that player's id.  E.g., if a player1 uses an empty cell, that cell now has the value :player1  scores is a map from ids to integers.  It includes score values for draws and for the two players.  When the game is over, turn is :none.  Otherwise, it describes which player's turn it is.  When a new game is created, turn is randomised  between the two players.  To play a turn, use the play-turn command.  For example, assuming 'g' is a predefined game:  (play-turn g 2)  Will produce a new game state with play progressed by one move,  in which the current player used cell 2.  Calling new-game clears the level data of a game and  randomises the initial player turn.  Scores are the  only preserved datum.  The following are game analysis functions:    get-play-state    - what state of play are we in?    get-turn          - whos turn is it?    get-scores        - get the scores    get-level-state   - get the state of the level    playing?          - are we still playing?    game-over?        - is the game over?    valid-move?       - is this a valid move?)(declare ;; Public Functions  ; Game Transforming  make-game  new-game  play-turn  ; Game Analysing  get-play-state  get-turn  get-scores  get-level-state  playing?  game-over?  valid-move?  ; Extra  get-game-grid)(declare ;; Private Functions  ^:private  ; Transforming  apply-move  next-turn  recalculate-state  ; Analysis  calculate-winner  try-combination);;  Utility functions(defmacro ^:private def-   A private version of def.   [& info] `(def ^:private ~@info))(defn- within-range   Determines if a value lies within an inclusive range.   [n x] (fn [v] (and (>= v n) (<= v x))));;  Initial data for making new games(def-   players               [:player1, :player2])(def-   initial-play-state    :playing)(def-   initial-level-state   (vec (repeat 9 nil)))(def-   initial-scores        {:player1 0, :player2 0, :draw 0})(defn-  random-turn []        (players (int (rand 2))))(def- winning-combinations [[1 2 3][4 5 6][7 8 9][1 5 9][3 5 7][1 4 7][2 5 8][3 6 9]]);;  Public Transforming Functions(defn make-game []   Creates a new game object.   { :play-state initial-play-state    :level-state initial-level-state    :scores initial-scores    :turn (random-turn) })(defn new-game [g]   Sets up a game object for the next play.   (assoc (make-game) :scores (get-scores g)))(defn play-turn [game move]   Progresses game-play by one move if possible.   (if (and (playing? game) (valid-move? game move))      (-> game        (apply-move move)        (recalculate-state)        (next-turn))      game));;  Private Transforming Functions(defn- apply-move [game move]   Progresses game-play by one move.   (assoc game    :level-state    (assoc (get-level-state game)      move      (get-turn game))))(defn- next-turn [game]   Updates which player should play next.    If no player is currently active, then    do not switch.   (assoc game    :turn    (case (get-turn game)        :none     :none        :player1  :player2        :player2  :player1)))(defn- recalculate-state [game]   Calculate if there is a winner. If so update    the play-state, turn, and scores; to reflect    the result.   (let [winner (calculate-winner game)        scores (get-scores game)]    (if (= winner :none)        game        (-> game          (assoc :play-state winner, :turn :none)          (update-in [:scores winner] inc)))));;  Private Analysis Functions(defn- calculate-winner [game]   Calculates if there is a winner.   (let [state (get-level-state game)        matching (partial try-combination state)]    (if (some matching winning-combinations)        (get-turn game)        (if (some nil? state)            :none            :draw))))(defn- try-combination [state [one two three]]   Calculates if a winning combination has occurred.   (let [lookup (comp (partial nth state) dec)        player (lookup one)]    (and      (not= player nil)      (= player (lookup two) (lookup three)))));;  Public Analysis Functions(def  get-play-state    :play-state)(def  get-turn          :turn)(def  get-scores        :scores)(def  get-level-state   :level-state)(defn playing? [game]   (= :playing (get-play-state game)))(def  game-over?        (comp not playing?))(defn valid-move? [game move]  (and ((within-range 0 8) move)       (nil? (nth (get-level-state game) move))));;  Public Extra Functions(defn get-game-grid [g]   Builds a simple string representation    of the current level state.   (clojure.string/join \n (map vec (partition 3 (get-level-state g)))))
Clojure TicTacToe (logic, no GUI)
functional programming;tic tac toe;clojure;lisp