commit 2388c2b29a4255582483889b391af42cee4f041a
parent db78854047b4f82f1b5404ce65c4d81acdc7162d
Author: Jared Tobin <jared@jtobin.ca>
Date: Thu, 16 Aug 2018 10:55:56 -0230
Cabal and stack.
Diffstat:
8 files changed, 215 insertions(+), 3 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -2,3 +2,4 @@ ti3sample
*swp
*.o
*.hi
+.stack-work
diff --git a/ChangeLog.md b/ChangeLog.md
@@ -0,0 +1,5 @@
+# Revision history for ti3-sampler
+
+## 0.1.0 -- 2018-08-16
+
+* Initial release.
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2018, Jared Tobin
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of Jared Tobin nor the names of other
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
@@ -1,18 +1,35 @@
-
# ti-sampler
Sample random board locations in a TI3 game.
Useful for e.g. setting domain counters only on some limited percentage of the
-board.
+board. I find chocking the board full of domain counters slows the game down a
+little too much, but you still want a few of them there for fun. A proportion
+of about 0.275 tiles seems to strike a very good balance.
+
+Supports three, four, five, and six player games. The tile coordinates are
+just reported in terms of position on the nth ring of the board. North is one,
+and then you just count clockwise from there.
+
+This takes into account the different board configurations for different
+players, and so doesn't sample home systems. Additionally, Mecatol Rex is
+always included in the result.
+
+For the three player game, just interpret the provided coordinates as if all
+tiles were present on the board.
## Usage
+Just clone the repo, install [Stack](https://www.haskellstack.org/), and run
+something like:
+
```
-$ stack runghc -- Sampler 4 0.1
+$ stack exec ti3-sampler 4 0.1
Outer 18
Outer 11
Mid 6
Rex
```
+The first argument is the number of players -- the second is the desired tile
+proportion.
diff --git a/Setup.hs b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Main.hs b/src/Main.hs
@@ -0,0 +1,129 @@
+{-# OPTIONS_GHC -Wall #-}
+
+import Control.Monad.Primitive
+import qualified Data.Map.Strict as MS
+import System.Random.MWC
+import System.Random.MWC.Distributions (bernoulli)
+import System.Environment
+
+data Players =
+ Three
+ | Four
+ | Five
+ | Six
+
+data Coord =
+ Rex
+ | Inner Int
+ | Mid Int
+ | Outer Int
+ deriving (Show, Eq, Ord)
+
+data Tile =
+ Special
+ | Plain Bool
+ deriving Show
+
+type Board = MS.Map Coord Tile
+
+empty :: Board
+empty = MS.fromList (zip coords (repeat (Plain False))) where
+ coords = mconcat [rex, inner, mid, outer]
+ rex = [Rex]
+ inner = fmap Inner [1..6]
+ mid = fmap Mid [1..12]
+ outer = fmap Outer [1..18]
+
+board :: Players -> Board
+board players = case players of
+ Three -> MS.alter special Rex
+ $ MS.alter special (Outer 4)
+ $ MS.alter special (Outer 5)
+ $ MS.alter special (Outer 6)
+ $ MS.alter special (Outer 9)
+ $ MS.alter special (Outer 10)
+ $ MS.alter special (Outer 11)
+ $ MS.alter special (Outer 15)
+ $ MS.alter special (Outer 16)
+ $ MS.alter special (Outer 17)
+ $ MS.alter special (Outer 1)
+ $ MS.alter special (Outer 7)
+ $ MS.alter special (Outer 13)
+ empty
+
+ Four -> MS.alter special Rex
+ $ MS.alter special (Outer 3)
+ $ MS.alter special (Outer 8)
+ $ MS.alter special (Outer 12)
+ $ MS.alter special (Outer 17)
+ empty
+
+ Five -> MS.alter special Rex
+ $ MS.alter special (Outer 3)
+ $ MS.alter special (Outer 7)
+ $ MS.alter special (Outer 10)
+ $ MS.alter special (Outer 13)
+ $ MS.alter special (Outer 17)
+ empty
+
+ Six -> MS.alter special Rex
+ $ MS.alter special (Outer 1)
+ $ MS.alter special (Outer 4)
+ $ MS.alter special (Outer 7)
+ $ MS.alter special (Outer 10)
+ $ MS.alter special (Outer 13)
+ $ MS.alter special (Outer 16)
+ empty
+ where
+ special :: Maybe Tile -> Maybe Tile
+ special tile = case tile of
+ Just Plain {} -> Just Special
+ _ -> tile
+
+primsample :: Double -> Board -> Gen RealWorld -> IO Board
+primsample prob brd gen = loop gen mempty (MS.toList brd)
+ where
+ loop prng acc tiles = case tiles of
+ [] -> return (MS.fromList acc)
+ (t:ts) -> case t of
+ (c, Plain False) -> do
+ coin <- bernoulli prob prng
+ loop prng ((c, Plain coin):acc) ts
+
+ _ -> loop prng (t:acc) ts
+
+sample :: Players -> Double -> IO Board
+sample players prob = withSystemRandom . asGenIO $
+ primsample prob (board players)
+
+render :: Board -> [Coord]
+render brd = loop mempty (MS.toList brd) where
+ loop acc tiles = case tiles of
+ [] -> acc
+ (t:ts) -> case t of
+ (Rex, _) -> loop (Rex:acc) ts
+ (c, Plain True) -> loop (c:acc) ts
+ _ -> loop acc ts
+
+main :: IO ()
+main = do
+ args <- getArgs
+ case args of
+ (n:p:_) -> do
+ let players = case (read n :: Int) of
+ 3 -> Just Three
+ 4 -> Just Four
+ 5 -> Just Five
+ 6 -> Just Six
+ _ -> Nothing
+
+ prob = read p :: Double
+
+ case players of
+ Nothing -> putStrLn "invalid number of players"
+ Just nps -> do
+ brd <- sample nps prob
+ mapM_ print (render brd)
+
+ _ -> putStrLn "USAGE: ./sample <NPLAYERS> <PROBABILITY>"
+
diff --git a/stack.yaml b/stack.yaml
@@ -0,0 +1,6 @@
+flags: {}
+packages:
+- '.'
+extra-deps: []
+resolver: lts-12.5
+
diff --git a/ti3-sampler.cabal b/ti3-sampler.cabal
@@ -0,0 +1,22 @@
+name: ti3-sampler
+version: 0.1.0
+synopsis: Sample random locations on a TI3 board.
+description: Sample random locations on a TI3 board.
+homepage: https://github.com/jtobin/ti3-sampler
+license: BSD3
+license-file: LICENSE
+author: Jared Tobin
+maintainer: jared@jtobin.io
+build-type: Simple
+extra-source-files: ChangeLog.md, README.md
+cabal-version: >=1.10
+
+executable ti3-sampler
+ main-is: Main.hs
+ hs-source-dirs: src
+ default-language: Haskell2010
+ build-depends:
+ base >= 4.10 && < 5
+ , containers >= 0.5 && < 0.6
+ , mwc-random >= 0.13 && < 0.15
+ , primitive >= 0.6 && < 0.7