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

Allow infinite count of items #656

Open
wants to merge 26 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Restyle with Fourmolu
  • Loading branch information
xsebek committed Oct 18, 2022
commit 94f47e883987bf68349b413988b1ca4db87f2b80
2 changes: 1 addition & 1 deletion src/Swarm/DocGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import Data.Text (Text, unpack)
import Data.Text qualified as T
import Data.Text.IO qualified as T
import Data.Tuple (swap)
import Swarm.Game.Entity (Entity, EntityMap (entitiesByName), entityName, loadEntities, Count)
import Swarm.Game.Entity (Count, Entity, EntityMap (entitiesByName), entityName, loadEntities)
import Swarm.Game.Entity qualified as E
import Swarm.Game.Recipe (Recipe, loadRecipes, recipeInputs, recipeOutputs, recipeRequirements)
import Swarm.Game.Robot (installedDevices, instantiateRobot, robotInventory)
Expand Down
5 changes: 2 additions & 3 deletions src/Swarm/Game/Entity.hs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ module Swarm.Game.Entity (
-- * Inventories
Inventory,
Count,
Number(..),
Number (..),

-- ** Construction
empty,
Expand Down Expand Up @@ -106,12 +106,12 @@ import GHC.Generics (Generic)
import Linear (V2)
import Swarm.Game.Display
import Swarm.Language.Capability
import Swarm.Language.Number (Number (..))
import Swarm.Util (dataNotFound, getDataFileNameSafe, plural, reflow, (?))
import Swarm.Util.Yaml
import Text.Read (readMaybe)
import Witch
import Prelude hiding (lookup)
import Swarm.Language.Number (Number (..))

------------------------------------------------------------
-- Properties
Expand Down Expand Up @@ -599,7 +599,6 @@ deleteAll e (Inventory cs byN h) =
where
n = (fst <$> IM.lookup (e ^. entityHash) cs) ? 0


-- | Get the entities in an inventory and their associated counts.
elems :: Inventory -> [(Count, Entity)]
elems (Inventory cs _ _) = IM.elems cs
Expand Down
27 changes: 14 additions & 13 deletions src/Swarm/Game/Step.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ import Data.Tuple (swap)
import Linear (V2 (..), zero, (^+^))
import Swarm.Game.CESK
import Swarm.Game.Display
import Swarm.Game.Entity hiding (empty, lookup, singleton, union, Integer)
import Swarm.Game.Entity qualified as E
import Swarm.Game.Entity (Number (..))
import Swarm.Game.Entity hiding (Integer, empty, lookup, singleton, union)
import Swarm.Game.Entity qualified as E
import Swarm.Game.Exception
import Swarm.Game.Recipe
import Swarm.Game.Robot
Expand All @@ -72,7 +73,6 @@ import System.Clock qualified
import System.Random (UniformRange, uniformR)
import Witch (From (from), into)
import Prelude hiding (lookup)
import Swarm.Game.Entity (Number(..))

-- | The main function to do one game tick. The only reason we need
-- @IO@ is so that robots can run programs loaded from files, via
Expand Down Expand Up @@ -1377,7 +1377,6 @@ execConst c vs s k = do
let salvageInventory = E.union (target ^. robotInventory) (target ^. installedDevices)
robotMap . at (target ^. robotID) . traverse . robotInventory .= salvageInventory


-- Copy over the salvaged robot's log, if we have one
inst <- use installedDevices
em <- use entityMap
Expand All @@ -1401,14 +1400,16 @@ execConst c vs s k = do
robotMap . at (target ^. robotID) . traverse . systemRobot .= True

ourID <- use @Robot robotID
let salvageItems = if system || creative
then []
else concatMap (uncurry replicateCount) (E.elems salvageInventory)
let salvageItems =
if system || creative
then []
else concatMap (uncurry replicateCount) (E.elems salvageInventory)
numItems = length salvageItems
replicateCount n e = e ^. entityName & case n of
E.Integer x -> replicate (fromIntegral x)
E.PosInfinity -> replicate 42
E.NegInfinity -> replicate (-42)
replicateCount n e =
e ^. entityName & case n of
E.Integer x -> replicate (fromIntegral x)
E.PosInfinity -> replicate 42
E.NegInfinity -> replicate (-42)
Comment on lines +1411 to +1412
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops, this is a problem. How should we salvage infinite inventory? 🤔

Copy link
Member Author

@xsebek xsebek Oct 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On IRC we agreed that it should take 1 tick. The idea is that an infinite item is like an item generator so we move it like it had count 1.

There is still an issue with how to do that. I think some "game state update" on the stack of the reprogrammed salvaged robot could work. An internal giveInfinite function also makes sense.


-- The program for the salvaged robot to run
let giveInventory =
Expand Down Expand Up @@ -1989,13 +1990,13 @@ safeDiv i 0 = return $ signum i * PosInfinity
safeDiv (Integer a) (Integer b) = return . Integer $ a `div` b
safeDiv (Integer _a) _ = return 0
safeDiv i b@(Integer _b) = return $ b * i
safeDiv _ _ = throwError $ CmdFailed Div "Dividing infinities"
safeDiv _ _ = throwError $ CmdFailed Div "Dividing infinities"

-- | Perform exponentiation, but fail on negative powers and negative number to the poer of infinity.
xsebek marked this conversation as resolved.
Show resolved Hide resolved
safeExp :: Has (Throw Exn) sig m => Number -> Number -> m Number
safeExp = \case
PosInfinity -> \b -> return $ PosInfinity * signum b
NegInfinity -> \b -> return $ NegInfinity * signum b
NegInfinity -> \b -> return $ NegInfinity * signum b
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

infinity ^ 0 ought to be 1, not 0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well spotted. 👍

Integer a -> \case
PosInfinity
| a == 0 -> return 0
Expand Down
2 changes: 1 addition & 1 deletion src/Swarm/Game/Value.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ import Data.Set.Lens (setOf)
import Data.Text (Text)
import GHC.Generics (Generic)
import Swarm.Language.Context
import Swarm.Language.Number (Number)
import Swarm.Language.Pretty (prettyText)
import Swarm.Language.Syntax
import Prelude
import Swarm.Language.Number (Number)

-- | A /value/ is a term that cannot (or does not) take any more
-- evaluation steps on its own.
Expand Down
4 changes: 2 additions & 2 deletions src/Swarm/Game/World.hs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ instance Wrapped Coords

-- | Convert an (x,y) location to a 'Coords' value.
locToCoords :: V2 Int64 -> Coords
locToCoords (V2 x y) = Coords (- y, x)
locToCoords (V2 x y) = Coords (-y, x)

-- | Convert 'Coords' to an (x,y) location.
coordsToLoc :: Coords -> V2 Int64
coordsToLoc (Coords (r, c)) = V2 c (- r)
coordsToLoc (Coords (r, c)) = V2 c (-r)

------------------------------------------------------------
-- World function
Expand Down
17 changes: 10 additions & 7 deletions src/Swarm/Language/Number.hs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE OverloadedStrings #-}

module Swarm.Language.Number (
Number(..),
Number (..),
) where
import GHC.Generics (Generic)

import Data.Data (Data)
import Data.Yaml (ToJSON (..))
import Data.Yaml.Aeson (FromJSON (..), Value (..))
import GHC.Generics (Generic)
import Swarm.Util.Yaml (FromJSONE)
import Data.Yaml.Aeson ( FromJSON(..), Value(..) )

-- | A type that represent the quantity of something.
--
Expand All @@ -33,8 +35,9 @@ instance FromJSON Number where
else fail "Integer is not a whole number!"
String "-inf" -> pure NegInfinity
String "inf" -> pure PosInfinity
e -> fail $
"Expected number or null for count, but got '" <> show e <> "'!"
e ->
fail $
"Expected number or null for count, but got '" <> show e <> "'!"

instance FromJSONE e Number

Expand Down Expand Up @@ -63,4 +66,4 @@ instance Num Number where
negate :: Number -> Number
negate (Integer c) = Integer (negate c)
negate NegInfinity = PosInfinity
negate PosInfinity = NegInfinity
negate PosInfinity = NegInfinity
2 changes: 1 addition & 1 deletion src/Swarm/Language/Parse.hs
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ import Data.Set.Lens (setOf)
import Data.Text (Text, index, toLower)
import Data.Text qualified as T
import Data.Void
import Swarm.Language.Number (Number (Integer))
import Swarm.Language.Syntax
import Swarm.Language.Types
import Text.Megaparsec hiding (runParser)
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer qualified as L
import Text.Megaparsec.Pos qualified as Pos
import Witch
import Swarm.Language.Number (Number(Integer))

-- Imports for doctests (cabal-docspec needs this)

Expand Down
3 changes: 1 addition & 2 deletions src/Swarm/Language/Pretty.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ import Prettyprinter.Render.String qualified as RS
import Prettyprinter.Render.Text qualified as RT
import Swarm.Language.Capability
import Swarm.Language.Context
import Swarm.Language.Number (Number (..))
import Swarm.Language.Syntax
import Swarm.Language.Typecheck
import Swarm.Language.Types
import Witch
import Swarm.Language.Number ( Number(..) )


-- | Type class for things that can be pretty-printed, given a
-- precedence level of their context.
Expand Down
2 changes: 1 addition & 1 deletion src/Swarm/Language/Requirement.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ import GHC.Generics (Generic)
import Swarm.Language.Capability (Capability (..), constCaps)
import Swarm.Language.Context (Ctx)
import Swarm.Language.Context qualified as Ctx
import Swarm.Language.Number (Number (..))
import Swarm.Language.Syntax hiding (Count)
import Swarm.Language.Number (Number(..))

-- | A /requirement/ is something a robot must have when it is
-- built. There are three types:
Expand Down
2 changes: 1 addition & 1 deletion src/Swarm/Language/Syntax.hs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ import Data.Text hiding (filter, map)
import Data.Text qualified as T
import GHC.Generics (Generic)
import Linear
import Swarm.Language.Number (Number)
import Swarm.Language.Types
import Witch.From (from)
import Swarm.Language.Number (Number)

------------------------------------------------------------
-- Constants
Expand Down
2 changes: 1 addition & 1 deletion test/unit/TestEval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import Data.Text (Text)
import Data.Text qualified as T
import Swarm.Game.State
import Swarm.Game.Value
import Swarm.Language.Number (Number (Integer, PosInfinity))
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import TestUtil
import Witch (from)
import Swarm.Language.Number (Number(Integer, PosInfinity))

testEval :: GameState -> TestTree
testEval g =
Expand Down