let it leave me like a long breath

let it dissipate or fade in the background

Feb. 11th, 2018

Profile

xax: purple-orange {11/3 knotwork star, pointed down (Default)
howling howling howling

Nav

  • Recent Entries
  • Archive
  • Reading
  • Tags
  • Memories
  • Profile

Tags

  • art - 2 uses
  • asteroid garden - 4 uses
  • code - 19 uses
  • demos - 1 use
  • dreams - 5 uses
  • ff7 fangame - 23 uses
  • fic prompts - 13 uses
  • gamedev challenge - 82 uses
  • hell game - 76 uses
  • nanowrimo - 11 uses
  • plants - 9 uses
  • process - 52 uses
  • programming - 51 uses
  • screenshots - 5 uses
  • writing log - 83 uses

May 2025

S M T W T F S
    123
45678 910
1112131415 1617
18192021222324
25262728293031
    • Previous Day
    • |
    • Next Day

    Feb. 11th, 2018

  • xax: purple-orange {11/3 knotwork star, pointed down (Default)
    Tags:
    • code,
    • gamedev challenge,
    • programming
    posted @ 02:50 pm

    hey i have a math problem i was hoping somebody could solve

    okay so as you may already know i wrote some haskell code for enumerating through values, and that was real neat and useful and generally speaking i accomplished a lot with it.

    now i'm trying to expand it. specifically: the code as written lets you enumerate through values, but in constructing the values any sense of relative position is lost. you can do something like V2 <$> from [1..10] <*> from [1..20] and that will let you enumerate through all 200 values, but if you have an index representing, say, V2 3 7 (index 62 btw) you can't say "i want to see the indices of all values that are one unit adjacent". basically there's no way to inspect a deck.

    SO i had the idea to track mergings of decks. change the data type to

    data Enumerable a = Enumerable
      { count :: Integer
      , segments :: [Integer]
      , selector :: Integer -> a
      }


    and make the applicative instance

    instance Applicative Enumerable where
      pure v = Enumerable 1 [1] $ const v
      (Enumerable c s f) <*> (Enumerable c' s' g) =
        Enumerable (c * c') (s <> ((c *) <$> s')) $ \i -> let
            j = i `mod` c
            k = i `div` c
          in f j $ g k


    so that V2 <$> from [1..10] <*> from [1..20] value would have 'segments' of [1,10], meaning that there are two axes: one that increases/decreases in steps of 1 and one that increases/decreases in steps of 10.

    and so then you can decompose indices into movements along those axes, like so:

    decompose :: Enumerable a -> Integer -> [Integer]
    decompose (Enumerable _ s _) i' = snd $ mapAccumR split i' s
      where
        split :: Integer -> Integer -> (Integer, Integer)
        split i c = (i `mod` c, i `div` c)


    and it will say: okay index 62 there decomposes to [2,6]. and then you can do something like...

    mutate :: Enumerable a -> [Integer] -> [[Integer]]
    mutate e i = tail $ recombine $ zip i mutvals
      where
        mutvals = uncurry spread <$> zip (maxAxes e) i
        spread m c = snd <$> filter fst
          [ (c > 0, c - 1)
          , (c < m, c + 1)
          ]
        recombine [] = [[]]
        recombine ((base,vars):rs) = ((:) <$> pure base <*> recombine rs)
          <> ((:) <$> vars <*> pure (fst <$> rs))
    
    maxAxes :: Enumerable a -> [Integer]
    maxAxes e = decompose e $ count e - 1
    
    mutateI :: Enumerable a -> Integer -> [Integer]
    mutateI e i = construct e <$> mutate e (decompose e i)
    


    to have it spit out all decomposed values that are one unit distant. so then:

    λ> let foo = ((,) <$> from [1..10] <*> from [1..20])
    λ> select foo 62
    Just (3,7)
    λ> mutateI foo 62
    [52,72,61,63]
    λ> select foo <$> mutateI foo 62
    [Just (3,6),Just (3,8),Just (2,7),Just (4,7)]


    and now you can navigate around within a enumerable deck. very neat. i'm currently using this to put together some really basic plant mutation/crossbreeding code (since you can also crossbreed two indices by decomposing them, and then picking values randomly from the two sets) and it's generally working pretty well.

    the PROBLEM is:

    the original formulation of Enumerable is also an Alternative and a Monoid:

    instance Alternative Enumerable where
      empty = Enumerable 0 $ const (error "no value")
      (Enumerable c v) <|> (Enumerable c' v') =
        Enumerable (c + c') $ \i -> case i - c of
          x | x >= 0 -> v' x
            | otherwise -> v i
    
    instance Monoid (Enumerable a) where
      mempty = empty
      mappend = (<|>)


    BUT: this new formulation would require some additional segment tracking. Applicative is really easy to store because it just creates n-dimensional prisms with totally regular axes. Alternative is a lot trickier, because it would involve... adding offsets? something? the actual lookup math above is really simple, but if i wanted to store that as a segment i'm pretty sure i would need to stop using just lists of integers.

    i've looked at a lot of math and i've tried to mark out the patterns it would make in indexing and i have yet to really figure out what i should do with it. i think the GOAL is to have it treat all choices as adjacent? so like pure 1 <|> pure 2 <|> pure 3 <|> pure 4 would be different from from [1,2,3,4] because the alternative would consider 1 adjacent to all of 2, 3, and 4, whereas the basic enumeration would only consider 1 adjacent to 2. (and then from [1,2] <|> from [3,4] <|> from [5,6] <|> from [7,8] would consider 1 and 2 to be adjacent to each other and to all of 3 5 and 7. ditto 3 & 4 with 1, 5, and 7.)

    it's just uhhhh i am totally failing to see whatever structure i need to see to codify that up, so, if anybody has any thoughts i would like to hear them.

    (spoilers this two-week project is gonna be trying to make something like this.)

    • Add Memory
    • Share This Entry
    • Link
    • 0 comments
    • Reply
    • Previous Day
    • |
    • Next Day
Page generated Sep. 29th, 2025 03:39 pm
Powered by Dreamwidth Studios

Style Credit

  • Style: (No Theme) for vertical