Code Monkey home page Code Monkey logo

hyperspace's People

Contributors

anjensan avatar fornever avatar hagane avatar rexim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hyperspace's Issues

Project revivification

I obviously don't know how to write network games. And I don't know how to write games at all.

That's the reason of current state of the project. Here's the list of things I thought were nice to have and tried to implement them:

  • a server for network games
  • clojurescript/WebGL graphics
  • Thrift-based protocol for client-server communications
  • JSON-based protocol for client-server communications

And here's the list of the successfully-implemented features:

(It's an empty list)

So, with all the today's experience and the knowledge that the failed non-working project is very hard to resurrect we need to make a new plan for the project. Main questions about the further project development:

  • Do we need a network server, or could it be a single-player game?

  • If we want a network game, then how should it work? Need a bit of game design docs (or at least a concept at the moment).

  • What minimal steps we should take to put the project back into the working state?

  • How should we organize the development to avoid project destabilization in future? (E.g. make a smooth migration from client-only to client-server architecture etc.)

Guys, please help me to plan the future.

Project requirements

Based on the current project state and its historical value (see #27), I propose the following.

Synopsis

Hyperspace should be a network multiplayer game for now designed for two players. It should consist of dedicated server application and a client application, both written in Clojure. Also, there should be a shared library of physical simulation functions used both by the client and the server code.

Game

Hyperspace is a turn-based physic simulator game. There're two players and a number of planets on the game field. Each player shoot a missile during each turn (but he could choose to skip the turn; that could also happen due to turn timeout); missiles behave as a bodies of mass in a static environment with Newtonian physics. Only missiles and planets have mass; missiles, planets and players also have a collision radius that should be taken into account by the simulation.

If the player is hit by enemy's missile, he's dead. If the missile hits the planet surface, then the missile explodes. If the missile hits the game world boundaries, it's considered "lost".

Player controls the shot power (in some diapason allowed by server) and direction.

The player turns are performed simultaneously. If both of the players are hit by enemy missiles at the same turn, the game is a tie.

Server

Server should provide HTTP API capable of:

  • register a new game
  • query game list
  • join a game
  • schedule the game turn
  • query the state of the game

When joining the game, server sends to the client a game key that should be used to schedule turns and query the game state.

When scheduling a turn, each client sends to the server their shot power and direction parameters.

When all the players in a game have been scheduled their turns, server simultaneously performs the turns.

When the client queries the game state, server sends the game map and the shot/direction history for each player. Shot information also contains a coordinates where the shot has been exploded and information whether any of players was hit by the collision.

Each game should have a round timeout. If any of the clients haven't scheduled their turn in time, their shooting phase should be skipped.

Client

Client is a desktop application. It should have two windows:

  • game lobby that shows the game list, allows to register a new game and to join an existing one
  • battlefield window that allows to choose shoot parameters and view the shot trajectory after both of the players have done their turns

The game client should calculate the trajectory itself using the same library as the server, and render the missile at its way to the target. But it should respect server decisions on whether any of the players was hit by the bullet, and show the point where the server reported a bullet collision. (In general, server and client calculations should be almost the same, but they could differ due to floating point arithmetic; server obviously always have the priority in case of any desyncronization.)

cannot start on osx

osx10.9, java7/8

$ lein run                                                                                                                                                                                                            
JavaVM WARNING: JAWT_GetAWT must be called after loading a JVM
Exception in thread "main" org.lwjgl.LWJGLException: Could not get the JAWT interface
    at org.lwjgl.opengl.AWTSurfaceLock.lockAndInitHandle(Native Method)
    at org.lwjgl.opengl.AWTSurfaceLock.access$100(AWTSurfaceLock.java:51)
    at org.lwjgl.opengl.AWTSurfaceLock$1.run(AWTSurfaceLock.java:94)
    at org.lwjgl.opengl.AWTSurfaceLock$1.run(AWTSurfaceLock.java:92)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.lwjgl.opengl.AWTSurfaceLock.privilegedLockAndInitHandle(AWTSurfaceLock.java:92)
    at org.lwjgl.opengl.AWTSurfaceLock.lockAndGetHandle(AWTSurfaceLock.java:66)
    at org.lwjgl.opengl.MacOSXCanvasPeerInfo.initHandle(MacOSXCanvasPeerInfo.java:57)
    at org.lwjgl.opengl.MacOSXDisplayPeerInfo.doLockAndInitHandle(MacOSXDisplayPeerInfo.java:56)
    at org.lwjgl.opengl.PeerInfo.lockAndGetHandle(PeerInfo.java:85)
    at org.lwjgl.opengl.MacOSXContextImplementation.create(MacOSXContextImplementation.java:47)
    at org.lwjgl.opengl.ContextGL.<init>(ContextGL.java:132)
    at org.lwjgl.opengl.Display.create(Display.java:847)
    at org.lwjgl.opengl.Display.create(Display.java:754)
    at org.lwjgl.opengl.Display.create(Display.java:736)
    at hyperspace.ui$setup_ui.invoke(ui.clj:124)
    at hyperspace.ui$start_ui.invoke(ui.clj:154)
    at hyperspace.main$_main.doInvoke(main.clj:7)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at clojure.lang.Var.invoke(Var.java:411)
    at user$eval672.invoke(form-init6915732820426289453.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6511)
    at clojure.lang.Compiler.eval(Compiler.java:6501)
    at clojure.lang.Compiler.load(Compiler.java:6952)
    at clojure.lang.Compiler.loadFile(Compiler.java:6912)
    at clojure.main$load_script.invoke(main.clj:283)
    at clojure.main$init_opt.invoke(main.clj:288)
    at clojure.main$initialize.invoke(main.clj:316)
    at clojure.main$null_opt.invoke(main.clj:349)
    at clojure.main$main.doInvoke(main.clj:427)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:419)
    at clojure.lang.AFn.applyToHelper(AFn.java:163)
    at clojure.lang.Var.applyTo(Var.java:532)
    at clojure.main.main(main.java:37)

Remove duplicate code from `richworld` namespace

See this:

;; FIXME: Duplicate code
new-missiles (->> missiles
(filter #(circle-X-rectangle? % world))
(remove #(circle-X-any-circle % planets))
(map #(simulation/update-particle % planets simulation/simulation-step)))
new-fragments (->> fragments
(concat broken-particles)
(filter #(circle-X-rectangle? % world))
(remove #(circle-X-any-circle % planets))
(map #(simulation/update-particle % planets simulation/simulation-step)))

Game management API

We need an API for managing game-related information: creating new games, game listing and joining games.

Build is unstable

Sometimes, the build on CI may be stuck. I think that we'll fix this by migrating from Clojurephant eventually.

Web client

I'm just filing this issue to not forget the situation. We have an ancient branch named clojurescript, and it seems that it should have some outdated cljs stuff.

I think that it'll be eventually useful to write a client for Hyperspace in Clojurescript. That way, our players won't be forced to download the client, install the JVM etc.

But this task isn't planned for current iteration.

Midje tests

There are some midje tests (defined with facts) that aren't executed for now.

I also cannot even run them because of java.io.FileNotFoundException: Could not locate hyperspace/server/main__init.class or hyperspace/server/main.clj on classpath.

Database

We'll need a database (classically we use H2) for user data storage.

Game Server

(Excerpt from #29.)

Server should provide HTTP API capable of:

  • register a new game

  • query game list

  • join a game

    • When joining the game, server sends to the client a game key that should be used to schedule turns and query the game state.
  • schedule the game turn

    • When scheduling a turn, each client sends to the server their shot power and direction parameters.
    • When all the players in a game have been scheduled their turns, server simultaneously performs the turns.
  • query the state of the game

    • When the client queries the game state, server sends the game map and the shot/direction history for each player. Shot information also contains a coordinates where the shot has been exploded and information whether any of players was hit by the collision.
  • Each game should have a round timeout. If any of the clients haven't scheduled their turn in time, their shooting phase should be skipped.

Test client

We'll need a test client accessing our swagger API.

User management API

We need an API (and a database structure) for user registration and logging in.

Gaming API

Players need an API for planning the turns and getting the turn results. I will maybe break this task to multiple smaller tasks later.

Bullet trajectory presentation

We need a compact way to present the bullet trajectory.

My research using differential equations does not seem to end with a great success, so maybe we need something more simple.

One example is presentation of current calculated trajectory as a group of Bezier curves.

Client doesn't start

$ lein run client
Exception in thread "main" java.lang.NullPointerException, compiling:(T:\Temp\form-init7564624643793564877.clj:1:78)
        at clojure.lang.Compiler.load(Compiler.java:7391)
        at clojure.lang.Compiler.loadFile(Compiler.java:7317)
        at clojure.main$load_script.invokeStatic(main.clj:275)
        at clojure.main$init_opt.invokeStatic(main.clj:277)
        at clojure.main$init_opt.invoke(main.clj:277)
        at clojure.main$initialize.invokeStatic(main.clj:308)
        at clojure.main$null_opt.invokeStatic(main.clj:342)
        at clojure.main$null_opt.invoke(main.clj:339)
        at clojure.main$main.invokeStatic(main.clj:421)
        at clojure.main$main.doInvoke(main.clj:384)
        at clojure.lang.RestFn.invoke(RestFn.java:421)
        at clojure.lang.Var.invoke(Var.java:383)
        at clojure.lang.AFn.applyToHelper(AFn.java:156)
        at clojure.lang.Var.applyTo(Var.java:700)
        at clojure.main.main(main.java:37)
Caused by: java.lang.NullPointerException
        at clojure.lang.Numbers.ops(Numbers.java:1013)
        at clojure.lang.Numbers.multiply(Numbers.java:148)
        at clojure.lang.Numbers.multiply(Numbers.java:3740)
        at hyperspace.client.ui$render_player.invokeStatic(ui.clj:98)
        at hyperspace.client.ui$render_player.invoke(ui.clj:88)
        at hyperspace.client.ui$render_world.invokeStatic(ui.clj:117)
        at hyperspace.client.ui$render_world.invoke(ui.clj:105)
        at hyperspace.client.ui$ui_loop.invokeStatic(ui.clj:148)
        at hyperspace.client.ui$ui_loop.invoke(ui.clj:136)
        at hyperspace.client.ui$start.invokeStatic(ui.clj:157)
        at hyperspace.client.ui$start.invoke(ui.clj:154)
        at hyperspace.client.main$run.invokeStatic(main.clj:6)
        at hyperspace.client.main$run.doInvoke(main.clj:5)
        at clojure.lang.RestFn.invoke(RestFn.java:397)
        at clojure.lang.AFn.applyToHelper(AFn.java:152)
        at clojure.lang.RestFn.applyTo(RestFn.java:132)
        at clojure.core$apply.invokeStatic(core.clj:646)
        at clojure.core$apply.invoke(core.clj:641)
        at hyperspace.main$_main.invokeStatic(main.clj:7)
        at hyperspace.main$_main.doInvoke(main.clj:5)
        at clojure.lang.RestFn.invoke(RestFn.java:410)
        at clojure.lang.Var.invoke(Var.java:379)
        at user$eval5.invokeStatic(form-init7564624643793564877.clj:1)
        at user$eval5.invoke(form-init7564624643793564877.clj:1)
        at clojure.lang.Compiler.eval(Compiler.java:6927)
        at clojure.lang.Compiler.eval(Compiler.java:6917)
        at clojure.lang.Compiler.load(Compiler.java:7379)
        ... 14 more

user module is disabled

While investigating #44, I've found that even if we fix the dependency issues, the server isn't able to work:

lein ring server
2021-08-19 23:05:25.001:INFO::main: Logging initialized @1177ms
WARNING: vector already refers to: #'clojure.core/vector in namespace: potemkin.utils, being replaced by: #'clj-tuple/vector
WARNING: hash-map already refers to: #'clojure.core/hash-map in namespace: potemkin.utils, being replaced by: #'clj-tuple/hash-map
Syntax error macroexpanding clojure.core/fn at (azql\expression.clj:209:1).
operator-/ - failed: vector? at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
operator-/ - failed: (or (nil? %) (sequential? %)) at: [:fn-tail :arity-n] spec: :clojure.core.specs.alpha/params+body

azql seems to cause some problems in macro expansion which prevents server from starting. For now, I had to disable the user server module because of that (#46).

Fix the failing tests

We currently have some tests that are not working. We need to fix that somehow.

I think that probably some of them are testing some deprecated stuff and can be safely removed.

Turn management on the client

GUI client should properly access a server turn management API:

  • schedule turns
  • query turn results
  • show turn timeout
  • animate shot results, show endgame table (whether the current player lost or won)

See #13 and #29 for details.

Migrate to Gradle

According to my current plans, this project should be able to build/test using Gradle.

Requires:

Server doesn't start

All I get now is:

$ lein ring server
clojure.lang.Compiler$CompilerException: Syntax error macroexpanding clojure.core/fn at (clojure/core/unify.clj:83:18).
#:clojure.error{:phase :macro-syntax-check, :line 83, :column 18, :source "clojure/core/unify.clj", :symbol clojure.core/fn}
 at clojure.lang.Compiler.checkSpecs (Compiler.java:6972)
    clojure.lang.Compiler.macroexpand1 (Compiler.java:6988)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:7093)
    clojure.lang.Compiler.analyze (Compiler.java:6789)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:7095)
    clojure.lang.Compiler.analyze (Compiler.java:6789)
    clojure.lang.Compiler.access$300 (Compiler.java:38)
    clojure.lang.Compiler$DefExpr$Parser.parse (Compiler.java:596)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:7107)
    clojure.lang.Compiler.analyze (Compiler.java:6789)
    clojure.lang.Compiler.analyze (Compiler.java:6745)
    clojure.lang.Compiler.eval (Compiler.java:7181)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:421)
    clojure.core.contracts.impl.transformers$eval691$loading__6721__auto____692.invoke (transformers.clj:1)
    clojure.core.contracts.impl.transformers$eval691.invokeStatic (transformers.clj:1)
    clojure.core.contracts.impl.transformers$eval691.invoke (transformers.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    leinjacker.defconstrainedfn$eval685$loading__6721__auto____686.invoke (defconstrainedfn.clj:1)
    leinjacker.defconstrainedfn$eval685.invokeStatic (defconstrainedfn.clj:1)
    leinjacker.defconstrainedfn$eval685.invoke (defconstrainedfn.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:669)
    clojure.core$use.invokeStatic (core.clj:6093)
    clojure.core$use.doInvoke (core.clj:6093)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    leinjacker.deps$eval677$loading__6721__auto____678.invoke (deps.clj:1)
    leinjacker.deps$eval677.invokeStatic (deps.clj:1)
    leinjacker.deps$eval677.invoke (deps.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:436)
    leiningen.ring.server$eval669$loading__6721__auto____670.invoke (server.clj:1)
    leiningen.ring.server$eval669.invokeStatic (server.clj:1)
    leiningen.ring.server$eval669.invoke (server.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:669)
    clojure.core$use.invokeStatic (core.clj:6093)
    clojure.core$use.doInvoke (core.clj:6093)
    clojure.lang.RestFn.invoke (RestFn.java:551)
    leiningen.ring$eval663$loading__6721__auto____664.invoke (ring.clj:1)
    leiningen.ring$eval663.invokeStatic (ring.clj:1)
    leiningen.ring$eval663.invoke (ring.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    leiningen.core.utils$require_resolve.invokeStatic (utils.clj:102)
    leiningen.core.utils$require_resolve.invoke (utils.clj:95)
    leiningen.core.utils$require_resolve.invokeStatic (utils.clj:105)
    leiningen.core.utils$require_resolve.invoke (utils.clj:95)
    leiningen.core.main$lookup_task_var.invokeStatic (main.clj:69)
    leiningen.core.main$lookup_task_var.invoke (main.clj:65)
    leiningen.core.main$pass_through_help_QMARK_.invokeStatic (main.clj:79)
    leiningen.core.main$pass_through_help_QMARK_.invoke (main.clj:73)
    leiningen.core.main$task_args.invokeStatic (main.clj:82)
    leiningen.core.main$task_args.invoke (main.clj:81)
    leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:339)
    leiningen.core.main$resolve_and_apply.invoke (main.clj:336)
    leiningen.core.main$_main$fn__7420.invoke (main.clj:453)
    leiningen.core.main$_main.invokeStatic (main.clj:442)
    leiningen.core.main$_main.doInvoke (main.clj:439)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.main$main_opt.invokeStatic (main.clj:514)
    clojure.main$main_opt.invoke (main.clj:510)
    clojure.main$main.invokeStatic (main.clj:664)
    clojure.main$main.doInvoke (main.clj:616)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.main.main (main.java:40)
Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/fn did not conform to spec.
#:clojure.spec.alpha{:problems ({:path [:fn-tail :arity-1 :params], :pred clojure.core/vector?, :val clojure.core.unify/var-unify, :via [:clojure.core.specs.alpha/params+body
 :clojure.core.specs.alpha/param-list :clojure.core.specs.alpha/param-list], :in [0]} {:path [:fn-tail :arity-n], :pred (clojure.core/fn [%] (clojure.core/or (clojure.core/ni
l? %) (clojure.core/sequential? %))), :val clojure.core.unify/var-unify, :via [:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/params+body], :in [0]}), :spec
#object[clojure.spec.alpha$regex_spec_impl$reify__2509 0x2d5f7182 "clojure.spec.alpha$regex_spec_impl$reify__2509@2d5f7182"], :value (clojure.core.unify/var-unify [G__801 G__
802 G__803 G__804] (clojure.core/if-let [vb__794__auto__ (G__804 G__802)] (clojure.core.unify/garner-unifiers G__801 vb__794__auto__ G__803 G__804) (clojure.core/if-let [vexp
r__795__auto__ (clojure.core/and (G__801 G__803) (G__804 G__803))] (clojure.core.unify/garner-unifiers G__801 G__802 vexpr__795__auto__ G__804) (if (clojure.core.unify/occurs
? G__801 G__802 G__803 G__804) (throw (java.lang.IllegalStateException. (clojure.core/str "Cycle found in the path " G__803))) (clojure.core.unify/bind-phase G__804 G__802 G_
_803))))), :args (clojure.core.unify/var-unify [G__801 G__802 G__803 G__804] (clojure.core/if-let [vb__794__auto__ (G__804 G__802)] (clojure.core.unify/garner-unifiers G__801
 vb__794__auto__ G__803 G__804) (clojure.core/if-let [vexpr__795__auto__ (clojure.core/and (G__801 G__803) (G__804 G__803))] (clojure.core.unify/garner-unifiers G__801 G__802
 vexpr__795__auto__ G__804) (if (clojure.core.unify/occurs? G__801 G__802 G__803 G__804) (throw (java.lang.IllegalStateException. (clojure.core/str "Cycle found in the path "
 G__803))) (clojure.core.unify/bind-phase G__804 G__802 G__803)))))}
 at clojure.spec.alpha$macroexpand_check.invokeStatic (alpha.clj:705)
    clojure.spec.alpha$macroexpand_check.invoke (alpha.clj:697)
    clojure.lang.AFn.applyToHelper (AFn.java:156)
    clojure.lang.AFn.applyTo (AFn.java:144)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.lang.Compiler.checkSpecs (Compiler.java:6970)
    clojure.lang.Compiler.macroexpand1 (Compiler.java:6988)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:7093)
    clojure.lang.Compiler.analyze (Compiler.java:6789)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:7095)
    clojure.lang.Compiler.analyze (Compiler.java:6789)
    clojure.lang.Compiler.access$300 (Compiler.java:38)
    clojure.lang.Compiler$DefExpr$Parser.parse (Compiler.java:596)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:7107)
    clojure.lang.Compiler.analyze (Compiler.java:6789)
    clojure.lang.Compiler.analyze (Compiler.java:6745)
    clojure.lang.Compiler.eval (Compiler.java:7181)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:421)
    clojure.core.contracts.impl.transformers$eval691$loading__6721__auto____692.invoke (transformers.clj:1)
    clojure.core.contracts.impl.transformers$eval691.invokeStatic (transformers.clj:1)
    clojure.core.contracts.impl.transformers$eval691.invoke (transformers.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    leinjacker.defconstrainedfn$eval685$loading__6721__auto____686.invoke (defconstrainedfn.clj:1)
    leinjacker.defconstrainedfn$eval685.invokeStatic (defconstrainedfn.clj:1)
    leinjacker.defconstrainedfn$eval685.invoke (defconstrainedfn.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:669)
    clojure.core$use.invokeStatic (core.clj:6093)
    clojure.core$use.doInvoke (core.clj:6093)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    leinjacker.deps$eval677$loading__6721__auto____678.invoke (deps.clj:1)
    leinjacker.deps$eval677.invokeStatic (deps.clj:1)
    leinjacker.deps$eval677.invoke (deps.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:436)
    leiningen.ring.server$eval669$loading__6721__auto____670.invoke (server.clj:1)
    leiningen.ring.server$eval669.invokeStatic (server.clj:1)
    leiningen.ring.server$eval669.invoke (server.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:669)
    clojure.core$use.invokeStatic (core.clj:6093)
    clojure.core$use.doInvoke (core.clj:6093)
    clojure.lang.RestFn.invoke (RestFn.java:551)
    leiningen.ring$eval663$loading__6721__auto____664.invoke (ring.clj:1)
    leiningen.ring$eval663.invokeStatic (ring.clj:1)
    leiningen.ring$eval663.invoke (ring.clj:1)
    clojure.lang.Compiler.eval (Compiler.java:7177)
    clojure.lang.Compiler.eval (Compiler.java:7166)
    clojure.lang.Compiler.load (Compiler.java:7636)
    clojure.lang.RT.loadResourceScript (RT.java:381)
    clojure.lang.RT.loadResourceScript (RT.java:372)
    clojure.lang.RT.load (RT.java:459)
    clojure.lang.RT.load (RT.java:424)
    clojure.core$load$fn__6839.invoke (core.clj:6126)
    clojure.core$load.invokeStatic (core.clj:6125)
    clojure.core$load.doInvoke (core.clj:6109)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.core$load_one.invokeStatic (core.clj:5908)
    clojure.core$load_one.invoke (core.clj:5903)
    clojure.core$load_lib$fn__6780.invoke (core.clj:5948)
    clojure.core$load_lib.invokeStatic (core.clj:5947)
    clojure.core$load_lib.doInvoke (core.clj:5928)
    clojure.lang.RestFn.applyTo (RestFn.java:142)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$load_libs.invokeStatic (core.clj:5985)
    clojure.core$load_libs.doInvoke (core.clj:5969)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invokeStatic (core.clj:667)
    clojure.core$require.invokeStatic (core.clj:6007)
    clojure.core$require.doInvoke (core.clj:6007)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    leiningen.core.utils$require_resolve.invokeStatic (utils.clj:102)
    leiningen.core.utils$require_resolve.invoke (utils.clj:95)
    leiningen.core.utils$require_resolve.invokeStatic (utils.clj:105)
    leiningen.core.utils$require_resolve.invoke (utils.clj:95)
    leiningen.core.main$lookup_task_var.invokeStatic (main.clj:69)
    leiningen.core.main$lookup_task_var.invoke (main.clj:65)
    leiningen.core.main$pass_through_help_QMARK_.invokeStatic (main.clj:79)
    leiningen.core.main$pass_through_help_QMARK_.invoke (main.clj:73)
    leiningen.core.main$task_args.invokeStatic (main.clj:82)
    leiningen.core.main$task_args.invoke (main.clj:81)
    leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:339)
    leiningen.core.main$resolve_and_apply.invoke (main.clj:336)
    leiningen.core.main$_main$fn__7420.invoke (main.clj:453)
    leiningen.core.main$_main.invokeStatic (main.clj:442)
    leiningen.core.main$_main.doInvoke (main.clj:439)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.core$apply.invokeStatic (core.clj:665)
    clojure.main$main_opt.invokeStatic (main.clj:514)
    clojure.main$main_opt.invoke (main.clj:510)
    clojure.main$main.invokeStatic (main.clj:664)
    clojure.main$main.doInvoke (main.clj:616)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.lang.Var.applyTo (Var.java:705)
    clojure.main.main (main.java:40)

Game lobby

Create a GUI application (I suggest JavaFX, but Swing is acceptable) to access a server lobby API (see #12 and #29 for explanations).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.