CulturedUrbanite VideoGame Selects.

Finished it just now.

Narrative-wise it's probably as good as a sci-fi game can get in terms of narrative. Very few games reach this level of writing, I struggle to name any - to be honest.
Gameplay has some one really big flaw (extreme time wasting due to many different factors) - but other than that it's a nice little puzzle game with a unique twist, I don't think any game has done this before. The space exploration had a lot of creativity, a lot of different fleshed out ideas - despite the execution being on the time-waste side often.

Maybe a masterpiece - but probably just a bible clone.

1 Like

Okay. Cruelty squad time.

My next game is Alien Soldier (On the Sega Megadrive)

1 Like

No play Cruelty Squad

I'll play Cruelty Squad if you play Dustforce to completion.

I remember that game. I never played it.

U
It's not that long anyways right

3 Likes

deleted

@Matticus

Was unable to complete my task.

The little diagrams show it should be possible (?); Collapse each value at X, then compute the masks for each of them. Reduce with & the entirety of the masks with the state.

import "lib/github.com/diku-dk/cpprandom/random"
module d = uniform_int_distribution i64 minstd_rand

def iota_u8 k = map (u8.i64) (iota k)

-- https://futhark-lang.org/examples/searching.html
def find_index 'a [n] (p: a -> bool) (as: [n]a): i64 =
  let op (x, i) (y, j) =
    if x && y then if i < j
                   then (x, i)
                   else (y, j)
    else if y then (y, j)
    else (x, i)
  in (reduce_comm op (false, -1) (zip (map p as) (iota n))).1

-- Indexing this with [box, iteration] fetches the (x, y) value we should utilize.
let LUT = [[(0i64, 0i64), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)],
           [(3, 1), (4, 1), (5, 1), (3, 2), (4, 2), (5, 2), (3, 0), (4, 0), (5, 0)],
           [(6, 2), (7, 2), (8, 2), (6, 0), (7, 0), (8, 0), (6, 1), (7, 1), (8, 1)],
           [(1, 3), (2, 3), (0, 4), (1, 4), (2, 4), (0, 5), (1, 5), (2, 5), (0, 3)],
           [(4, 4), (5, 4), (3, 5), (4, 5), (5, 5), (3, 3), (4, 3), (5, 3), (3, 4)],
           [(7, 5), (8, 5), (6, 3), (7, 3), (8, 3), (6, 4), (7, 4), (8, 4), (6, 5)],
           [(2, 6), (0, 7), (1, 7), (2, 7), (0, 8), (1, 8), (2, 8), (0, 6), (1, 6)],
           [(5, 7), (3, 8), (4, 8), (5, 8), (3, 6), (4, 6), (5, 6), (3, 7), (4, 7)],
           [(8, 8), (6, 6), (7, 6), (8, 6), (6, 7), (7, 7), (8, 7), (6, 8), (7, 8)]]

def collapse state rng =
  let (rng, random) = d.rand(0, 8) rng
  let valid_indices = map2 (*) state 
    -- Range from 1..9; 0..8 will result in the first index always being '0' which is a null.
    (map (+ 1) (iota_u8 9))
  |> rotate random

  let index = foldl(\a b -> if a > 0 then a else b) 0 valid_indices
  in (rng, (i64.u8 (index - 1))) -- Undo the above (+ 1).

def mask index x y = 
  -- Given a position (u, v), compute which sudoku box we're within.
  let box u v =             -- 0 1 2
    if u < 3 then           -- 3 4 5
      if v < 3 then 0       -- 6 7 8
      else if v < 6 then 3
      else 6
    else if u < 6 then
      if v < 3 then 1
      else if v < 6 then 4
      else 7
    else
      if v < 3 then 2
      else if v < 6 then 5
      else 8

  -- Return something akin to [1, 1, 1, 1, 0, 1, 1, 1, 1].
  let mask_at_index k = 
    map2 (^) (replicate 9 1u8) (rotate (9 - k) [1u8, 0, 0, 0, 0, 0, 0, 0, 0])

  in let mask_fn u v = 
    if x == u && y == v         -- Collapsed this state.
      then (rotate (9 - index) [1u8, 0, 0, 0, 0, 0, 0, 0, 0])
    else if x == u || y == v    -- Perpendicular lines with the origin at (x, y).
      then mask_at_index index
    else if box x y == box u v  -- Resides in the same sudoku box.
      then mask_at_index index
    else
      replicate 9 1u8

  in map (\v -> map (\u -> mask_fn u v) (iota 9)) (iota 9)

def wfc seed =
  let rng = minstd_rand.rng_from_seed [seed]
  let rngs = minstd_rand.split_rng 9 rng

  let initial_state = replicate 9 (replicate 9 (replicate 9 1u8))

  let (_, state, _) =
    loop (rngs, state, acc) = (rngs, initial_state, 0) for acc < 9 do
      let coords = map (\box -> LUT[box, acc]) (iota 9) -- fetch the indices to collapse.
      let (rngs, indices) = map2 (\(x, y) rng -> collapse state[x, y] rng) coords rngs |> unzip
      let masks = map2 (\index (x, y) -> mask index x y) indices coords

      -- TODO: Rather than flatten and coalesce to a size at runtime, map (&) over [9][9][9].
      let flattened_masks = map (\m -> flatten_3d m :> [729]u8) masks
      let flattened_state = flatten_3d state :> [729]u8
      let flattened_state = reduce_comm (map2 (&)) flattened_state flattened_masks

      let state = unflatten_3d 9 9 9 flattened_state

    in (rngs, state, acc + 1)
  
  -- Find the first non-zero value within each state.
  in map (\x -> map (\y -> find_index (\a -> a != 0) state[x, y]) (iota 9)) (iota 9)

in a REPL

[16]> collapse [1, 0, 1, 1, 1, 0, 0, 0, 0] rng
(1946104754u32, 0i64)
[17]> collapse [1, 0, 1, 1, 1, 1, 0, 0, 0] rng
(1946104754u32, 5i64)
[20]> mask 0 0 0
[[[1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]],
 [[0u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
  [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8]]]

The compiler is telling me acc is unused, which doesn't make any sense to me...

futhark check wfc.fut            
Warning at wfc.fut:76:60-62:
Unused variable "acc" .

I have been bested.

1 Like
75,76c75,76
<   let (_, state, _) =
<     loop (rngs, state, acc) = (rngs, initial_state, 0) for acc < 9 do
---
>   let (_, state) =
>     loop (rngs, state) = (rngs, initial_state) for acc < 9 do
81,84c81,82
<       -- TODO: Rather than flatten and coalesce to a size at runtime, map (&) over [9][9][9].
<       let flattened_masks = map (\m -> flatten_3d m :> [729]u8) masks
<       let flattened_state = flatten_3d state :> [729]u8
<       let flattened_state = reduce_comm (map2 (&)) flattened_state flattened_masks
---
>       let and_3d a b = map (\x -> map (\y -> map (\z -> a[x, y, z] & b[x, y, z]) (iota 9)) (iota 9)) (iota 9)
>       let state = reduce_comm (and_3d) state masks
86c84,87
<       let state = unflatten_3d 9 9 9 flattened_state
---
>       -- TODO: Rather than flatten and coalesce to a size at runtime, map (&) over [9][9][9].
>       -- let flattened_masks = map (\m -> flatten_3d m :> [729]u8) masks
>       -- let flattened_state = flatten_3d state :> [729]u8
>       -- let flattened_state = reduce_comm (map2 (&)) flattened_state flattened_masks
88c89
<     in (rngs, state, acc + 1)
---
>     in (rngs, state)
91c92
<   in map (\x -> map (\y -> find_index (\a -> a != 0) state[x, y]) (iota 9)) (iota 9)
---
>   in state

Yeah this is hilarious.

1 Like

I'll be honest, it would take me hours to understand this code since I've never used Rust. I should learn it but I tend to avoid technical things that aren't immediately beneficial for personal use for game development. I'm a game developer first, and a programmer second.

At this point I find C++ incredibly easy to use since I had to work on an engine written in pure C for years, so learning Rust hasn't made sense to learn yet -- especially since it isn't widely adopted by UE4 or Unity.

1 Like

no the code is effectively parallel standard ML.

if you can't reason about the rust playground like you're just an old ■■■■■■■

I interpret your bullying as empathy. Thank you.

2 Likes

I basically only program in languages that render me completely unemployable nowadays.

1 Like

I am at a loss as to why this doesn't work.

1 Like

@big_ass

1 Like

Working on my new Unity Game.

4 Likes

Me too isn't that just a warning