Search code examples
swiftrandomarc4random

Avoiding repetition with arc4random in Swift


I have the following code to generate a randomly populated grid in Swift:

import Foundation

var tile = [String](count: 900, repeatedValue: ".")

// Randomly populate the grid with hashes
for i in 0...400 {
    tile[Int(arc4random_uniform(899))] = "#"
}

// Print the grid to console
for y in 0...(29) {
    for x in 0...(29) {
        print("\(tile[y * 10 + x])")
    }
    println("")
}

Running this code produces a grid which looks like the following:

..##..#.#...#..#..#.#.####.#..
..#..#..#.#.####.#....###.#.#.
#.####.#....###.#.#.#####.....
..###.#.#.#####.....#...#....#
#####.....#...#....###.##.###.
#...#....###.##.###..#.....#..
##.##.###..#.....#...##..#.##.
.#.....#...##..#.##...#.####..
.##..#.##...#.####..###..#.#.#
..#.####..###..#.#.#.#..#.....
###..#.#.#.#..#.........#...##
.#..#.........#...##.##.......
....#...##.##............#...#
.##............#...####....##.
.....#...####....##..#.#.....#
###....##..#.#.....#........#.
.#.#.....#........#...#.#..#..
........#...#.#..#......#....#
..#.#..#......#....#.##.#...##
....#....#.##.#...###...#..#..
.##.#...###...#..#..#.#..#...#
#...#..#..#.#..#...#####...##.
#.#..#...#####...##..#.......#
####...##..#.......#.#.#.....#
.#.......#.#.#.....##.........
.#.#.....##..........##.#..#.#
#..........##.#..#.##.#.#.....
.##.#..#.##.#.#.....##...#....
#.#.#.....##...#......#.##....
##...#......#.##.....#.######.

You can clearly see that a pattern is repeating itself. Is there a way to "throw" function so that the generation is more convincing?


Solution

  • Your print function is wrong: tile[y*10 + x] should be tile[y*30 + x].


    As for generating grids: what, precisely, do you want?

    If the answer is "a random choice from the uniform distribution over the space of all possible 30x30 grids, where each cell is either # or .", then you should simply choose each cell with equal probability of # and .:

    for i in 0..<900 {
        // arc4random_uniform(2) is either 0 or 1, with equal probability
        tile.append(arc4random_uniform(2) == 0 ? "." : "#")
    }
    

    If the answer is "a random choice from the uniform distribution over 30x30 grids in which exactly 400 cells are #", then you should choose 400 unique indexes up front, before converting them to #.

    As is, your code may produce grids with only one # (though it is very unlikely). And it will never produce grids with more than 400 #s.