This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-01-24
Channels
- # announcements (22)
- # babashka (33)
- # babashka-sci-dev (161)
- # beginners (25)
- # calva (57)
- # cider (6)
- # clara (6)
- # clerk (14)
- # clj-kondo (24)
- # clojars (10)
- # clojure (65)
- # clojure-austin (1)
- # clojure-conj (2)
- # clojure-europe (23)
- # clojure-miami (3)
- # clojure-nl (3)
- # clojure-norway (3)
- # clojure-uk (3)
- # clojurescript (28)
- # cursive (24)
- # datomic (136)
- # emacs (38)
- # graalvm (29)
- # graphql (3)
- # introduce-yourself (8)
- # jackdaw (4)
- # jobs-discuss (9)
- # malli (5)
- # nbb (36)
- # off-topic (11)
- # pathom (58)
- # polylith (2)
- # practicalli (1)
- # re-frame (5)
- # reagent (11)
- # releases (1)
- # remote-jobs (8)
- # sci (15)
- # shadow-cljs (31)
- # slack-help (2)
- # spacemacs (11)
- # sql (7)
- # tools-build (9)
I have made a tic-tac-toe game in clojure, to get a feel of everything. I would be very glad if anyone could take a look at it and let me know of any improvements I dont know if this is too much spam, so i will paste the code in a reply to this
(def start-board [[1 2 3]
[4 5 6]
[7 8 9]])
(defn print-board! [board]
(println)
(doseq [row board]
(println row)))
(defn winner? [rows]
(or (some #(every? (fn [c] (= c \x)) %) rows)
(some #(every? (fn [c] (= c \o)) %) rows)))
(defn transpose [m]
(apply mapv vector m))
(defn game-won? [board]
(let [winner-rows? (winner? board)
columns (transpose board)
winner-col? (winner? columns)
diagonal (map-indexed (fn [i row] (nth row i)) board)
winner-diagonal (winner? [diagonal])
anti-diagonal (reverse (map-indexed (fn [i row] (nth row i)) (reverse board)))
winner-anti-diagonal (winner? [anti-diagonal])]
(or winner-rows? winner-col? winner-diagonal winner-anti-diagonal)))
(defn board-full? [board]
(every? char? (flatten board)))
(defn legal-move? [board move]
(and (<= 1 move 9)
(integer? (get-in board [(int (Math/ceil (quot (dec move) 3))) (mod (dec move) 3)]))))
(defn make-move [board move turn]
(update-in board [(int (Math/ceil (quot (dec move) 3))) (mod (dec move) 3)] (constantly turn)))
(def next-turn {\x \o
\o \x})
(defn get-move! [turn]
(printf "%s's turn. Please select a square\n" turn)
(println "___________")
(Integer/parseInt (read-line)))
(defn run-game []
(loop [board start-board
turn \x]
(print-board! board)
(cond
(game-won? board) (format "%s is the WINNER" (next-turn turn))
(board-full? board) "DRAW"
:else (let [move (get-move! turn)]
(if (legal-move? board move)
(recur (make-move board move turn) (next-turn turn))
(do (println "Please select a valid square")
(recur board turn)))))))
I think this is cool and not spammy, especially since you posted the code in a reply. There is also #C053PTJE6, just FYI.
(defn winner? [rows]
(or (some #(every? #{\x} %) rows)
(some #(every? #{\o} %) rows)))
diagonal
and anti-diagonal
- you can also try this:
(mapv #(%1 %2) [[1 2 3]
[4 5 6]
[7 8 9]] (range 3))
=> [1 5 9]
(mapv #(%1 %2) [[1 2 3]
[4 5 6]
[7 8 9]] [2 1 0])
=> [3 5 7]
legal-move?
and make-move
- repeated code, move it into the function:
(defn move->yx [n]
(let [d (dec n)]
[(quot d 3) (mod d 3)]))
make-move
- I guess you need assoc-in
get-move!
- Integer/parseInt -> parse-long
Thank you very much for your feedback! I use this approach for the diagonal and anti-diagonal because i had some thought that i might want to extend the board size in the future. I've used your suggestion for legal-move and moved the repeated code into a new function. But i might have to refactor this anyways if i make it possible to change the board size Thank you again :)
The code looks pretty good/idiomatic to me.
user=> (->> (clojure.reflect/reflect Character) :members (filter #(= 'isUpperCase (:name %))) (map :parameter-types))
([char] [int])
user=>
Don't think of it as casting though, a String is not castable to a char, a String is a list of Chars, it's like if you said if we can cast a List of int to an int, it doesn't make logical sense. So start thinking of a String like a collection of Characters, a String of one element is a Collection of one Character.
Just stumbled over something that so often got me confused as a beginner, so while it may be obvious to most professionals, I thought it may help some people to write about it: When you evaluate an expression with a very large value/sequence in the REPL or via the editor and it seems to freeze your editor/environment, remember that your value is being printed, which can have a huge impact on performance. So even though an evaluation would otherwise take just a second to compute, it could take much, much longer if it is printed directly instead of being stored in a var or reduced to a smaller value.
...and stored in a var is faster because the repl prints the var, not the contents of the var
you can control content printing with
(set! *print-length* 50)
(set! *print-level* 2) ;; depth
I am trying to write identity function in anonymous function shorthand. I tried following code:
(map (fn [x] x) [1 2 3]) => (1 2 3)
(map #(%) [1 2 3]) => Error printing return value (ClassCastException) at etl/eval7963$fn (form-init6095319328514486799.clj:25).
As per my understanding both approaches should work.
Although when I write anonymous function to double the value of elements, the following way it works as expected.
(map #(* % 2) [1 2 3]) => (2 4 6)
Can anyone please help me understand why #(%)
is not working?if #(+ % %)
is the same as (fn [x] (+ x x))
then what is #(+ %)
then what is #(+)
then what is #(%)
Hmm… makes sense the error is also indicating that class java.lang.Long cannot be cast to class clojure.lang.IFn
😞 probably should’ve read that carefully.
This confused many of us at first! Also watch out for e.g. (map #([%]) (range 3))
which, for the same reason, does not do what one might expect.
That won't work ... Try (map identity [1 2 3]) which is not anonymous or (map #(do %) [1 2 3]) which uses anonymous function form but is not idiomatic. This #(%) is not allowed as % is not a function, but in this case it is an integer. So for instance you can't do this (1) and expect it to execute, since 1 is not a function.