That way, you know the data you're getting is definitely valid, and you can go ahead and use it. Using this, you could ask for a player's move in a manner more like: (ask-for-input (format-question choices) As mentioned aboveĬhoices) Maps return nil (falsey) for a invalid key I nearly always need a prompt, a way to validate, and to display an error message, so this has proved very helpful.
ROCK PAPER SCISSORS ONLINE GENERATOR CODE
Yes, this has a lot of side effects, but I've found that any time I needed to ask for, and validate user input, this is essentially what I come up with, so I decided to just wrap that common code in a function. (recur prompt-message error-message validate-f))))) Newlines aren't added after the messages." "Prompts the user for input, checks it using the validation function, and displays the error if the validation fails. My personal library function that I use for getting simple console input is: (defn ask-for-input You never do any input validation! I got some real funky results by entering nonsense. Here, it could be argued that using println is forcing the user to only print to the console, but you'd likely need to rewrite the procedure for another circumstance anyway, so this isn't a huge problem. The idea is to create pure functions wherever possible, and section the side-effect causing functions off and test them separately. Even the strictest Haskell programs have to have a procedure somewhere. and consequently play-round: Of course, where you tie everything together, you're going to have some side effects. That way, the user can use a StringStream if they just want the formatted String. You could also pass in a Stream (like *out* to print to the stdout), and print into the Stream. What if you made this program networked in the future, and wanted to use the same functionality? I'd prefer to create format- functions, and println the returns from them. They're compiling the data together into a String, and displaying the String. The display- functions: These functions are arguably doing too much. Get-input: You need to get input from the user, and have sectioned the functionality off into a single function that you use everywhere. Really, you only have a few impure aspects of your program: I was wondering if there is a better / more elegant / more clojure-y way to deal with side effects? Most of my suggestions will be stylistic, or based on little things I've learned that have helped me. I don't really have much bad to say about it. (println (format "%s has won the round" (get-round-winner-name players round-winner)))) (display-round-intro choices user-choice computer-choice) (update-player-choice :computer computer-choice) Round-winner (get-round-winner user-choice computer-choice) (let [user-choice (-> (get-input) keyword)Ĭomputer-choice (get-random-choice choices) "Display the key question - Rock, Paper, Scissors?" (println (format "%s vs %s" (get choices user-choice) (get choices computer-choice)))) (println (format "%s won the game with the score of %s to %s" Otherwise return the original state of players"Ĭhecking that both scores are % :score ( user-score comp-score)Ĭomp-name (get-in players )]
ROCK PAPER SCISSORS ONLINE GENERATOR UPDATE
"If there is a winner, update the winner's score (and (= user-choice :s) (= computer-choice :p))) :user (and (= user-choice :p) (= computer-choice :r)) (or (and (= user-choice :r) (= computer-choice :s)) "Waits for user to enter text and hit enter, then cleans the input" Or perhaps I'm being paranoid, because after all, an application without side - effects is useless. The game works fine, but I was wondering if there is a better / more elegant / more clojure-y way to deal with side effects?įor example, the body of my play-round function is just a bunch of printlns and it doesn't return anything (well, nil by default).Īnd I tried to keep such functions to a minimum, but still. I followed braveclojure book and built this little command line Rock, Paper, Scissors game.