Skip to content
This repository has been archived by the owner on May 20, 2024. It is now read-only.

Commit

Permalink
Merge branch 'issue/29'
Browse files Browse the repository at this point in the history
  • Loading branch information
Henry J. Wylde committed Apr 2, 2016
2 parents ebaae28 + d91546b commit f9aba63
Show file tree
Hide file tree
Showing 21 changed files with 138 additions and 126 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

### Upcoming

*Major*

* Added required `--tag` option for enabling multiple games at once. ([#29](https://github.com/hjwylde/werewolf/issues/29))

### v0.4.12.0

*Minor*
Expand Down
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ All werewolf commands are designed to be run by a user from the chat client.
E.g., to start a game:

```bash
> werewolf --caller @foo start --extra-roles seer @bar @baz @qux @quux @corge @grault
> werewolf --caller @foo --tag werewolf start --extra-roles seer @bar @baz @qux @quux @corge @grault
{"ok":true,"messages":[
{"to":null,"message":"A new game of werewolf is starting with @foo, @bar, @baz, @qux, @quux, @corge, @grault!"},
{"to":null,"message":"The roles in play are Seer (1), Simple Villager (4), Simple Werewolf (2) for a total balance of -2."},
Expand All @@ -123,8 +123,10 @@ E.g., to start a game:
```

In this example, user _@foo_ ran the `start` command with the player names as arguments.
Note that the calling user, _@foo_ was passed in to the `--caller` option.
All commands require this option.
Note that the calling user, _@foo_, was passed in to the `--caller` option and a game tag,
_werewolf_, was passed in to the `--tag` option.
All commands require these options (n.b., the tag option is arbitrary, it just enables multiple
games of werewolf to be running at once).

Any command ran returns a JSON result.
The result contains a boolean for whether the command was successful and a list of messages.
Expand All @@ -134,7 +136,7 @@ The `to` header on a message may either be `null`---for a public message---or ha
It's the Seer's turn now.

```bash
> werewolf --caller @corge see @grault
> werewolf --caller @corge --tag werewolf see @grault
{"ok":true,"messages":[
{"to":"@corge","message":"@grault is aligned with the Werewolves."},
{"to":"@quux","message":"You feel restless, like an old curse is keeping you from sleep. It seems you're not the only one... @grault are also emerging from their homes."},
Expand All @@ -148,11 +150,11 @@ It's the Seer's turn now.
Let's have the Werewolves, _@quux_ and _@grault_, vote to devour a Villager.

```bash
> werewolf --caller @quux vote @foo
> werewolf --caller @quux --tag werewolf vote @foo
{"ok":true,"messages":[
{"to":"@grault","message":"@quux voted to devour @foo."}
]}
> werewolf --caller @grault vote @foo
> werewolf --caller @grault --tag werewolf vote @foo
{"ok":true,"messages":[
{"to":"@quux","message":"@grault voted to devour @foo."},
{"to":null,"message":"The sun rises. Everybody wakes up and opens their eyes..."},
Expand All @@ -165,14 +167,14 @@ Let's have the Werewolves, _@quux_ and _@grault_, vote to devour a Villager.
Too bad for _@foo_. Maybe the village can get some vengeance...

```bash
> werewolf --caller @corge vote @grault
> werewolf --caller @corge --tag werewolf vote @grault
{"ok":true,"messages":[]}
```

This time, even though the command was successful, there are no messages.

```bash
> werewolf --caller @corge vote @grault
> werewolf --caller @corge --tag werewolf vote @grault
{"ok":false,"messages":[{"to":"@corge","message":"You've already voted!"}]}
```

Expand All @@ -182,9 +184,9 @@ Even though the command was unsuccessful, the chat interface probably won't need
Relaying the error message back to the user should suffice.

Thus a chat interface must implement the following:
* The ability to call werewolf commands. This includes passing the `--caller` option and arguments
correctly. It is possible to only implement the `interpret` command, which interprets the
caller's input.
* The ability to call werewolf commands. This includes passing the `--caller` and `--tag` options
and arguments correctly. It is possible to only implement the `interpret` command, which
interprets the caller's input.
* The ability to send resultant messages. Resultant messages may be to everyone or to a specific
user.

Expand Down
44 changes: 22 additions & 22 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,31 @@ main = getArgs >>= run
run :: [String] -> IO ()
run args = handleParseResult (execParserPure werewolfPrefs werewolfInfo args) >>= handle

interpret :: Text -> [Text] -> IO ()
interpret callerName args = do
let result = execParserPure werewolfPrefs werewolfInfo (map T.unpack $ "--caller":callerName:args)
interpret :: Text -> Text -> [Text] -> IO ()
interpret callerName tag args = do
let result = execParserPure werewolfPrefs werewolfInfo (map T.unpack $ "--caller":callerName:"--tag":tag:args)

case result of
Success options -> handle options
_ -> handle (Options callerName . Help . Help.Options . Just $ Help.Commands False)
_ -> handle (Options callerName tag . Help . Help.Options . Just $ Help.Commands False)

handle :: Options -> IO ()
handle (Options callerName command) = case command of
Choose options -> Choose.handle callerName options
Boot options -> Boot.handle callerName options
Circle options -> Circle.handle callerName options
End options -> End.handle callerName options
Heal -> Heal.handle callerName
Help options -> Help.handle callerName options
Interpret (Interpret.Options args) -> interpret callerName args
Pass -> Pass.handle callerName
Ping -> Ping.handle callerName
Poison options -> Poison.handle callerName options
Protect options -> Protect.handle callerName options
Quit -> Quit.handle callerName
Reveal -> Reveal.handle callerName
See options -> See.handle callerName options
Start options -> Start.handle callerName options
Status -> Status.handle callerName
handle (Options callerName tag command) = case command of
Choose options -> Choose.handle callerName tag options
Boot options -> Boot.handle callerName tag options
Circle options -> Circle.handle callerName tag options
End options -> End.handle callerName tag options
Heal -> Heal.handle callerName tag
Help options -> Help.handle callerName tag options
Interpret (Interpret.Options args) -> interpret callerName tag args
Pass -> Pass.handle callerName tag
Ping -> Ping.handle callerName tag
Poison options -> Poison.handle callerName tag options
Protect options -> Protect.handle callerName tag options
Quit -> Quit.handle callerName tag
Reveal -> Reveal.handle callerName tag
See options -> See.handle callerName tag options
Start options -> Start.handle callerName tag options
Status -> Status.handle callerName tag
Version -> Version.handle callerName
Vote options -> Vote.handle callerName options
Vote options -> Vote.handle callerName tag options
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Boot.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ data Options = Options
{ argTarget :: Text
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options targetName) = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options targetName) = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = bootCommand callerName targetName

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game', messages) -> writeGame game' >> exitWith success { messages = messages }
Right (game', messages) -> writeGame tag game' >> exitWith success { messages = messages }
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Choose.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ data Options = Options
{ args :: [Text]
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options args) = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options args) = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = case game ^. stage of
ScapegoatsTurn -> Scapegoat.chooseCommand callerName args
Expand All @@ -56,4 +56,4 @@ handle callerName (Options args) = do

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game, messages) -> writeGame game >> exitWith success { messages = messages }
Right (game, messages) -> writeGame tag game >> exitWith success { messages = messages }
8 changes: 4 additions & 4 deletions app/Werewolf/Command/Circle.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ data Options = Options
{ optIncludeDead :: Bool
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options includeDead) = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options includeDead) = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = circleCommand callerName includeDead

Expand Down
10 changes: 5 additions & 5 deletions app/Werewolf/Command/End.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ data Options = Options
{ optForce :: Bool
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options force) = do
unlessM doesGameExist $ exitWith failure { messages = [noGameRunningMessage callerName] }
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options force) = do
unlessM (doesGameExist tag) $ exitWith failure { messages = [noGameRunningMessage callerName] }

unless force $ do
game <- readGame
game <- readGame tag

unless (doesPlayerExist callerName game) $
exitWith failure { messages = [playerCannotDoThatMessage callerName] }

deleteGame
deleteGame tag

exitWith success { messages = [gameEndedMessage] }
where
Expand Down
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Heal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,16 @@ import Game.Werewolf.Command.Witch
import Werewolf.Game
import Werewolf.Messages

handle :: MonadIO m => Text -> m ()
handle callerName = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> m ()
handle callerName tag = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = healCommand callerName

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game', messages) -> writeGame game' >> exitWith success { messages = messages }
Right (game', messages) -> writeGame tag game' >> exitWith success { messages = messages }
18 changes: 9 additions & 9 deletions app/Werewolf/Command/Help.hs
Original file line number Diff line number Diff line change
Expand Up @@ -45,28 +45,28 @@ data Command = Commands
{ optAll :: Bool
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options (Just (Commands optAll))) = do
mGame <- ifM (doesGameExist &&^ return (not optAll)) (Just <$> readGame) (return Nothing)
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options (Just (Commands optAll))) = do
mGame <- ifM (doesGameExist tag &&^ return (not optAll)) (Just <$> readGame tag) (return Nothing)

exitWith success
{ messages = map (privateMessage callerName) (commandsMessages callerName mGame)
}
handle callerName (Options (Just (Roles optAll))) = do
roles <- (sortBy (compare `on` view Role.name) . nub) <$> ifM (doesGameExist &&^ return (not optAll))
(toListOf (players . roles) <$> readGame)
handle callerName tag (Options (Just (Roles optAll))) = do
roles <- (sortBy (compare `on` view Role.name) . nub) <$> ifM (doesGameExist tag &&^ return (not optAll))
(toListOf (players . roles) <$> readGame tag)
(return allRoles)

exitWith success
{ messages = map (privateMessage callerName . roleMessage) roles
}
handle callerName (Options (Just (Rules optAll))) = do
mGame <- ifM (doesGameExist &&^ return (not optAll)) (Just <$> readGame) (return Nothing)
handle callerName tag (Options (Just (Rules optAll))) = do
mGame <- ifM (doesGameExist tag &&^ return (not optAll)) (Just <$> readGame tag) (return Nothing)

exitWith success
{ messages = map (privateMessage callerName) (rulesMessages mGame)
}
handle callerName (Options Nothing) = exitWith success
handle callerName _ (Options Nothing) = exitWith success
{ messages = map (privateMessage callerName) helpMessages
}

Expand Down
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Pass.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ import Game.Werewolf.Command.Witch as Witch
import Werewolf.Game
import Werewolf.Messages

handle :: MonadIO m => Text -> m ()
handle callerName = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> m ()
handle callerName tag = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = case game ^. stage of
DevotedServantsTurn -> DevotedServant.passCommand callerName
Expand All @@ -45,4 +45,4 @@ handle callerName = do

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game', messages) -> writeGame game' >> exitWith success { messages = messages }
Right (game', messages) -> writeGame tag game' >> exitWith success { messages = messages }
8 changes: 4 additions & 4 deletions app/Werewolf/Command/Ping.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ import Game.Werewolf.Command.Status
import Werewolf.Game
import Werewolf.Messages

handle :: MonadIO m => Text -> m ()
handle callerName = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> m ()
handle callerName tag = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = pingCommand callerName

Expand Down
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Poison.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ data Options = Options
{ argTarget :: Text
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options targetName) = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options targetName) = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = poisonCommand callerName targetName

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game', messages) -> writeGame game' >> exitWith success { messages = messages }
Right (game', messages) -> writeGame tag game' >> exitWith success { messages = messages }
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Protect.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ data Options = Options
{ argTarget :: Text
} deriving (Eq, Show)

handle :: MonadIO m => Text -> Options -> m ()
handle callerName (Options targetName) = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> Options -> m ()
handle callerName tag (Options targetName) = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = protectCommand callerName targetName

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game', messages) -> writeGame game' >> exitWith success { messages = messages }
Right (game', messages) -> writeGame tag game' >> exitWith success { messages = messages }
10 changes: 5 additions & 5 deletions app/Werewolf/Command/Quit.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ import Game.Werewolf.Command.Global
import Werewolf.Game
import Werewolf.Messages

handle :: MonadIO m => Text -> m ()
handle callerName = do
unlessM doesGameExist $ exitWith failure
handle :: MonadIO m => Text -> Text -> m ()
handle callerName tag = do
unlessM (doesGameExist tag) $ exitWith failure
{ messages = [noGameRunningMessage callerName]
}

game <- readGame
game <- readGame tag

let command = quitCommand callerName

case runExcept (runWriterT $ execStateT (apply command >> checkStage >> checkGameOver) game) of
Left errorMessages -> exitWith failure { messages = errorMessages }
Right (game', messages) -> writeGame game' >> exitWith success { messages = messages }
Right (game', messages) -> writeGame tag game' >> exitWith success { messages = messages }
Loading

0 comments on commit f9aba63

Please sign in to comment.