Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CLI option to start the game paused #2080

Merged
merged 6 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions app/game/Main.hs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{-# LANGUAGE ApplicativeDo #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}

-- |
-- SPDX-License-Identifier: BSD-3-Clause
module Main where
module Main (main) where

import Control.Monad (when)
import Data.Foldable qualified
Expand Down Expand Up @@ -44,25 +46,29 @@ cliParser :: Parser CLI
cliParser =
subparser
( mconcat
[ command "format" (info (Format <$> parseFormat) (progDesc "Format a file"))
[ command "run" (info (Run <$> appOpts <**> helper) (progDesc "Run the Swarm game (default)"))
, command "format" (info (Format <$> parseFormat) (progDesc "Format a file"))
, command "lsp" (info (pure LSP) (progDesc "Start the LSP"))
, command "version" (info (pure Version) (progDesc "Get current and upstream version."))
, command "keybindings" (info (ListKeybinding <$> initKeybindingConfig <*> printKeyMode <**> helper) (progDesc "List the keybindings"))
]
)
<|> Run
<$> ( AppOpts
<$> seed
<*> scenario
<*> run
<*> autoplay
<*> speedFactor
<*> cheat
<*> color
<*> webPort
<*> pure gitInfo
)
<|> Run <$> appOpts
where
appOpts :: Parser AppOpts
appOpts = do
let repoGitInfo = gitInfo
userSeed <- seed
userScenario <- scenario
scriptToRun <- run
pausedAtStart <- paused
autoPlay <- autoplay
speed <- speedFactor
cheatMode <- cheat
colorMode <- color
userWebPort <- webPort
return $ AppOpts {..}

input :: Parser FormatInput
input =
flag' Stdin (long "stdin" <> help "Read code from stdin")
Expand Down Expand Up @@ -108,6 +114,8 @@ cliParser =
scenario = optional $ strOption (long "scenario" <> short 'i' <> metavar "FILE" <> help "Name of an input scenario to load")
run :: Parser (Maybe String)
run = optional $ strOption (long "run" <> short 'r' <> metavar "FILE" <> help "Run the commands in a file at startup")
paused :: Parser Bool
paused = switch (long "paused" <> short 'p' <> help "Pause the game at start.")
autoplay :: Parser Bool
autoplay = switch (long "autoplay" <> short 'a' <> help "Automatically run the solution defined in the scenario, if there is one. Mutually exclusive with --run.")
speedFactor :: Parser Int
Expand Down
3 changes: 2 additions & 1 deletion src/swarm-engine/Swarm/Game/State.hs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import Swarm.Game.Location
import Swarm.Game.Robot
import Swarm.Game.Robot.Concrete
import Swarm.Game.Scenario.Status
import Swarm.Game.State.Config
import Swarm.Game.State.Landscape
import Swarm.Game.State.Robot
import Swarm.Game.State.Substate
Expand Down Expand Up @@ -457,7 +458,7 @@ initGameState :: GameStateConfig -> GameState
initGameState gsc =
GameState
{ _creativeMode = False
, _temporal = initTemporalState
, _temporal = initTemporalState $ startPaused gsc
, _winCondition = NoWinCondition
, _winSolution = Nothing
, _robotInfo = initRobots gsc
Expand Down
10 changes: 6 additions & 4 deletions src/swarm-engine/Swarm/Game/State/Runtime.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,23 @@ initGameStateConfig ::
, Has (Accum (Seq SystemFailure)) sig m
, Has (Lift IO) sig m
) =>
Bool ->
m GameStateConfig
initGameStateConfig = do
initGameStateConfig pause = do
gsi <- initGameStateInputs
appDataMap <- readAppData
nameGen <- initNameGenerator appDataMap
return $ GameStateConfig appDataMap nameGen gsi
return $ GameStateConfig appDataMap nameGen pause gsi

initRuntimeState ::
( Has (Throw SystemFailure) sig m
, Has (Accum (Seq SystemFailure)) sig m
, Has (Lift IO) sig m
) =>
Bool ->
m RuntimeState
initRuntimeState = do
gsc <- initGameStateConfig
initRuntimeState pause = do
gsc <- initGameStateConfig pause
scenarios <- loadScenarios $ gsiScenarioInputs $ initState gsc

return $
Expand Down
6 changes: 3 additions & 3 deletions src/swarm-engine/Swarm/Game/State/Substate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,11 @@ defaultRobotStepsPerTick = 100

-- * Record initialization

initTemporalState :: TemporalState
initTemporalState =
initTemporalState :: Bool -> TemporalState
initTemporalState pausedAtStart =
TemporalState
{ _gameStep = WorldTick
, _runStatus = Running
, _runStatus = if pausedAtStart then ManualPause else Running
, _ticks = TickNumber 0
, _robotStepsPerTick = defaultRobotStepsPerTick
}
Expand Down
2 changes: 2 additions & 0 deletions src/swarm-scenario/Swarm/Game/State/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ data GameStateConfig = GameStateConfig
{ initAppDataMap :: Map Text Text
, nameParts :: NameGenerator
-- ^ Lists of words/adjectives for use in building random robot names.
, startPaused :: Bool
-- ^ Start the game paused - useful for debugging or competitive play.
, initState :: GameStateInputs
}
3 changes: 2 additions & 1 deletion src/swarm-tournament/Swarm/Web/Tournament/Validate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ gamestateFromScenarioText content = do
withExceptT (ScenarioEnvironmentFailure . ContextInitializationFailure)
. ExceptT
. runThrow
$ evalAccum (mempty :: Seq SystemFailure) initGameStateConfig
. evalAccum (mempty :: Seq SystemFailure)
$ initGameStateConfig False

let scenarioInputs = gsiScenarioInputs $ initState gsc
scenarioObject <- initScenarioObject scenarioInputs content
Expand Down
10 changes: 9 additions & 1 deletion src/swarm-tui/Swarm/TUI/Controller/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,15 @@ import Swarm.Game.World qualified as W
import Swarm.Game.World.Coords
import Swarm.Language.Capability (Capability (CDebug))
import Swarm.Language.Syntax hiding (Key)
import Swarm.TUI.Model
import Swarm.TUI.Model (
AppState,
FocusablePanel,
ModalType (..),
Name (..),
gameState,
modalScroll,
uiState,
)
import Swarm.TUI.Model.Repl (REPLHistItem, REPLPrompt, REPLState, addREPLItem, replHistory, replPromptText, replPromptType)
import Swarm.TUI.Model.UI
import Swarm.TUI.View.Util (generateModal)
Expand Down
3 changes: 3 additions & 0 deletions src/swarm-tui/Swarm/TUI/Model.hs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ data AppOpts = AppOpts
-- ^ Scenario the user wants to play.
, scriptToRun :: Maybe FilePath
-- ^ Code to be run on base.
, pausedAtStart :: Bool
-- ^ Pause the game on start by default.
, autoPlay :: Bool
-- ^ Automatically run the solution defined in the scenario file
, speed :: Int
Expand All @@ -270,6 +272,7 @@ defaultAppOpts =
{ userSeed = Nothing
, userScenario = Nothing
, scriptToRun = Nothing
, pausedAtStart = False
, autoPlay = False
, speed = defaultInitLgTicksPerSecond
, cheatMode = False
Expand Down
4 changes: 2 additions & 2 deletions src/swarm-tui/Swarm/TUI/Model/StateUpdate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ initPersistentState ::
m (RuntimeState, UIState, KeyEventHandlingState)
initPersistentState opts@(AppOpts {..}) = do
(warnings :: Seq SystemFailure, (initRS, initUI, initKs)) <- runAccum mempty $ do
rs <- initRuntimeState
rs <- initRuntimeState pausedAtStart
ui <- initUIState speed (not (skipMenu opts)) cheatMode
ks <- initKeyHandlingState
return (rs, ui, ks)
Expand All @@ -142,7 +142,7 @@ constructAppState ::
AppOpts ->
m AppState
constructAppState rs ui key opts@(AppOpts {..}) = do
let gs = initGameState $ rs ^. stdGameConfigInputs
let gs = initGameState (rs ^. stdGameConfigInputs)
case skipMenu opts of
False -> return $ AppState gs (ui & uiGameplay . uiTiming . lgTicksPerSecond .~ defaultInitLgTicksPerSecond) key rs
True -> do
Expand Down
2 changes: 1 addition & 1 deletion test/bench/Benchmark.hs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ mkGameState prog robotMaker numRobots = do

-- NOTE: This replaces "classicGame0", which is still used by unit tests.
gs <- simpleErrorHandle $ do
(_ :: Seq SystemFailure, initRS) <- runAccum mempty initRuntimeState
(_ :: Seq SystemFailure, initRS) <- runAccum mempty $ initRuntimeState False
(scenario, _) <- loadStandaloneScenario "classic"
return $ pureScenarioToGameState scenario 0 0 Nothing $ view stdGameConfigInputs initRS

Expand Down