Hi! I'm making a game with Clojure. And I have a few code structure/design problems.
I have an atom with characters (a map of maps) in my main file. But because I don't want to make that file too big I have, for example, a file called "ai.clj" with AI stuff, that I require from the main file. For the monsters' AI to work, the AI needs to know the state of the world, i.e. the characters. My current solution is to (declare characters) and then have a (defn init-ai [characters] (def characters characters)) function in ai.clj that I call from the main file at the start of the game. It works, but it doesn't feel quite right. I don't want to have to pass the characters as an argument all the time, that seems a little bit too verbose to me. It seems somehow unnecessary to have to just pass the same atom around to all the functions. That's a general theme in my project: modules/files depend on the main module/file. And sometimes there's nothing I can do about it. The graphics engine I'm using, for example, insists that my application extends an "Application" class from the engine. And that the main loop is in that "app". So that's in my main file. But I really want the graphics module to be a separate thing to which I send things to be represented graphically. But, of course, the graphics module depends on the "app" instance in my main file. So I did for the graphics what I did for the AI. Another concern of mine is that there are so many places where I need to update the characters' state. There's the AI stuff, that updates the monsters with their targets and paths, etc. Other examples: when one character attacks another, then the health needs updating; or when the player moves. I have a doubts that I am doing this "the Clojure way." Often, the characters' ids are arguments to functions. For example, I have a function called physical-attack (the one I mentioned above) that takes the id of the attacker and the id of the target. Then it calculates how much damage the attack is supposed to do, and updates the target's health in the 'characters' atom. Sure, it could return the amount of damage instead, that would be one step towards purity. But to be really pure it would have to take the actual maps as arguments too. It may work in this case, but it's not always so easy to make the functions pure. The function that calls physical-attack, for example, also updates the attacker (he now has to wait before he can attack again), and returning both of the updated characters is not as nice as returning one. And the update still has to happen somewhere, because attacking *has* a side effect (in the game), so maybe it's ok. It's just that now the updates are spread out all over, and I thought that maybe it was better to have them in a special place in the code, for sturcture and sanity. A concrete problem: I want a function that takes the ids of two characters (because as I explained above that's more convenient) and checks if they are close enough to each other to attack. But I want to use the function in the ai file and in the main file. But I can't define it in some sort of utility file, because it depends on the characters atom. And it doesn't feel quite right to define it in ai.clj since 'characters' is defined in the main file, but the main file requires ai and not the other way around. I could also define the function in the main file and send it to the ai file as I did with 'characters' itself, but that seems really messy. Sure, this function could be functional, and that would solve these problems. But that would be inconvenient, because I would just have to look up the position of the characters in a lot more places instead, leading to increased code size. I just wanted to write down my problems and maybe get some comments on it. This being my first real Clojure project, I feel that I could use some guidance, so feel free to comment as much as you'd like. I realize that these are problems programmers deal with all the time (at least I think so), but I thought that maybe the Clojure community, being so wise, might have some answers. ;) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en