Fork me on GitHub
#clojure
<
2022-06-23
>
skykanin11:06:38

so I have this file

(ns snake)

(defn -main [& args]
  (println "Hello World here are my args")
  (println (apply str args)))
called snake.clj and I tried to invoke it from the CLI like so clj -M -m snake snake.clj, but I get the error
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate snake__init.class, snake.clj or snake.cljc on classpath.

p-himik11:06:27

The current directory is not no the classpath.

p-himik12:06:00

You can: • Change the classpath directly or via deps.edn • Put the file in the src directory (it's by default on the classpath) • Not use -main and instead load the file as a script

👍 1
simongray13:06:37

Apparently, resources are not considered files when accessed inside uberjars? I have a few calls to (io/file (io/resource ...)) since one consuming function in a library I’m using takes a File object. This works fine when I run the code in the REPL, but it errors out when I try to run my project from an uberjar. I have found this search result which leads me to believe I should use io/input-stream instead of io/file when accessing an io/resource inside an uberjar: https://groups.google.com/g/clojure/c/8scFidro4ow Can someone explain why there’s a difference when accessing resources in a REPL vs doing it via an uberjar? It seems a bit odd to me.

p-himik13:06:22

java.io.File is something that represents a file on a file system. A JAR by itself is such a file. Its contents are not files on a file system though.

Alex Miller (Clojure team)13:06:30

Files are loaded from the file system. Resources are loaded from the classpath (which can be files but it's an open URL-based system - theoretically the resources could come from a network location, or a database, or even be generated on the fly)

👍 1
simongray15:06:01

I see. I think I never really looked into what it means to be a Resource.

skykanin13:06:47

Does anyone have a guide on how to build an uberjar for an executable clojure file with a -main function using tools.build ?

Alex Miller (Clojure team)13:06:21

you might need some of the setup at the top of that too for deps.edn

skykanin13:06:35

Thanks that worked perfectly!

skykanin15:06:38

is it possible to import clojure.lang.PersistentQueue and give it a different name so I don't have to use the fully qualified name? I tried (:require [clojure.lang.PersistentQueue :as queue]) in my ns macro, but it complains Could not locate clojure/lang/PersistentQueue__init.class, clojure/lang/PersistentQueue.clj or clojure/lang/PersistentQueue.cljc on classpath.

dpsutton15:06:43

slack=> (import 'clojure.lang.PersistentQueue)
clojure.lang.PersistentQueue
slack=> PersistentQueue/EMPTY
#clojure.lang.PersistentQueue[]

dpsutton15:06:15

i don’t believe you can rename it but importing means you use it by its Classname instead of FQN (fully qualified name)

skykanin15:06:11

ah, and I have to use import because it's a java class right?

dpsutton15:06:30

import classes, require namespaces

Alex Miller (Clojure team)15:06:08

and technically, you never need to import, it is just a convenience to let you use unqualified class names in your code

skykanin15:06:25

even for classes from third party java libraries?

dpsutton15:06:23

slack=> (java.time.LocalDateTime/now)
#object[java.time.LocalDateTime
        "0x45894837"
        "2022-06-23T15:54:28.466801"]
vs
slack=> (import 'java.time.LocalDateTime)
java.time.LocalDateTime
slack=> (LocalDateTime/now)
#object[java.time.LocalDateTime
        "0x2b243553"
        "2022-06-23T15:55:07.813022"]
all the same up to convenience

👍 1
Kris C16:06:17

Is it still ok to start a web project with Ring? So many options (luminus, pedestal, yada)...

p-himik16:06:15

It's still OK. And probably the preferred option when you're just starting.

😃 1
skykanin16:06:01

(ns snake.core
  (:import (clojure.lang PersistentQueue)
           (java.awt Color Graphics Dimension Font)
           (javax.swing JFrame JPanel)
           (java.awt.event KeyEvent KeyAdapter))
  (:gen-class))

(def size 50)
(def scale 15)
(def start-length 5)
(def tick-speed 50) ; ms delay between each render loop
(def screen (Dimension. (* scale size) (* scale size)))
(def food-color Color/GREEN)
(def snake-color Color/WHITE)

(defn new-world []
  (let [head [40 25]
        body (take (dec start-length) (iterate (fn [[x y]] [(inc x) y]) head))]
    {:snake
       {:body  (apply conj PersistentQueue/EMPTY body)
        :head  head
        :dir   :w
        :size  3
        :dead? false}
     :food #{[50 32]}}))

(def next-point
  {:n [0 -1]
   :s [0 1]
   :e [1 0]
   :w [-1 0]})

(defn tick [{:keys [snake food] :as world}]
  (let [new-head (map + (next-point (:dir snake)) (:head snake))
        new-body (conj (.pop (:body snake)) (:head snake))]
    (-> world
        (assoc-in [:snake :head] new-head)
        (assoc-in [:snake :body] new-body))))

(defn draw-square [#^Graphics g [x y] c]
  (doto g
    (.setColor c)
    (.fillRect (* scale x) (* scale y) scale scale)
    (.setColor Color/BLACK)
    (.drawRect (* scale x) (* scale y) scale scale)))

(defn draw [#^Graphics g {:keys [snake food]}]
  (doto g
    (.setColor Color/BLACK)
    (.fillRect 0 0 (* scale size) (* scale size)))
  (doseq [snake (conj (:body snake) (:head snake))]
    (draw-square g snake snake-color)))

(def code->key
  {KeyEvent/VK_UP    :n
   KeyEvent/VK_DOWN  :s
   KeyEvent/VK_LEFT  :w
   KeyEvent/VK_RIGHT :e})

(defn draw-window []
  (let [world (atom (new-world))
        key-listener (proxy [KeyAdapter] []
                       (keyPressed [e]
                         (when-let [dir-key (code->key (.getKeyCode e))]
                           (swap! world #(assoc-in % [:snake :dir] dir-key)))))
        panel (doto (proxy [JPanel] [] (paint [#^Graphics g] (draw g @world)))
                  (.setMinimumSize screen)
                  (.setMaximumSize screen)
                  (.setPreferredSize screen))]
      (doto (JFrame. "Snaaaaaaaaaaake!")
          (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
          (.add panel)
          .pack
          (.setResizable false)
          (.setLocationRelativeTo nil)
          (.setVisible true)
          (.addKeyListener key-listener))
      (loop []
        (swap! world tick)
        (.repaint panel)
        (Thread/sleep tick-speed))
        (recur))))

(defn -main [& _]
  (draw-window))
So I have this snake game that uses java swing for the UI with a very basic render loop that uses thread sleep to manage how often I repaint the JPanel. However the animation isn't very smooth and so I was wondering if there is a way to make the animation smoother.

👍 1
hiredman16:06:59

draw intermediate frames

skykanin16:06:01

How could I do that?

hiredman16:06:55

so you draw things in frame A and you draw different things in frame B and that change is animation, but the change is too abrupt, so figure out something that is halfway between A and B, and draw it in the middle

p-himik16:06:25

A couple of other things to consider: • 50 ms means 20 FPS - quite low • If a single repaint and all associated computations take a lot of time, with your current code it'll be on top of those 50 ms, reducing FPS even further

hiredman16:06:17

the process of doing this will disentangle scene state and your data model, you'll likely end up ticking through your model generating some kind of scene graph and throwing that on a queue to be rendered whenever

richiardiandrea17:06:17

Hi there, I was looking at https://tomfaulhaber.github.io/autodoc/ and I was wondering if there is a way to use it with the clojure tools cli

Alex Miller (Clojure team)17:06:12

the real question is whether you can use it at all :)

Alex Miller (Clojure team)17:06:44

unfortuntely, autodoc has some glorious stuff wrapped in many layers of pain

richiardiandrea17:06:14

oh ok thanks for the heads up 😄

Alex Miller (Clojure team)17:06:10

if you want to go spelunking, https://github.com/clojure/contrib-api-doc is the code that is used to build contrib api docs and it (kind of) uses the clojure cli (a very old version is vendored into that repo under cli/)

❤️ 1
lread17:06:54

@richiardiandrea if you aren’t already in love with autodoc, you might also consider https://github.com/borkdude/quickdoc, or https://github.com/weavejester/codox or hosting your docs on https://cljdoc.org/.

richiardiandrea17:06:47

thank you, and yes I tried both of them yesterday and they were both having some issues (opened now against the repos) in our code base

borkdude17:06:34

@richiardiandrea I just replied on one of the issues. The other issue can easily be solved (source link)

richiardiandrea17:06:53

Yep great thanks a lot for answering!

borkdude18:06:19

@richiardiandrea Implemented the source link template now