4

I'm trying to create a word jumbler game for the iPhone using Swift. I'm relatively new to programming and Swift, but have created this game in Python previously.

Here is my pseudo-code:

//select RANDOM WORD from array

//determine the number of characters in the RANDOMLY SELECTED WORD

//randomly select a NUMBER within the boundries of the number of characters (i.e. if the word is "apple," select a number between 0 and 4)

//select the CHARACTER that corresponds to the randomly selected NUMBER

//add the CHARACTER to a new string (JUMBLE)

//remove the CHARCATER from the RANDOMLY SELECTED WORD

//Repeat until the RANDOM WORD is empty

Here is my code so far:

import UIKit

//this is my array/word bank
var words = ["Apple", "Orange", "Pear"]

//this selects a random word in the array
var selectedWord = words[Int(arc4random_uniform(UInt32(words.count)))]

//this counts the number of characters in the string
var length = (countElements(selectedWord))

//this randomly selects a position within the string
var position = Int(arc4random_uniform(UInt32(length)))

//this creates a new string consiting of the letter found in the position from the previous line of code
var subString = selectedWord[advance(selectedWord.startIndex, position)]

My issues is that I cannot figure out how to remove the selected character from the selected word. If I could, I'd simply create a loop where I repeat the process above until the original word is empty

Lyndsey Scott
  • 37,080
  • 10
  • 92
  • 128
Gabe Levin
  • 45
  • 1
  • 6
  • where do you want to remove the characters? could you please indicate that in the code? – ProgrammingIsAwsome Jan 04 '15 at 01:52
  • So basically you're just trying to mix up the characters of your string? – Lyndsey Scott Jan 04 '15 at 01:55
  • Exactly, I'm trying to mix up the characters in my randomly selected string. My initial thought was to create a loop that will randomly select characters from my string until the string is empty, but I'm open to doing it another way. – Gabe Levin Jan 04 '15 at 01:58

5 Answers5

6

Swift 5 or later

extension RangeReplaceableCollection  { 
    /// Returns a new collection containing this collection shuffled
    var shuffled: Self {
        var elements = self
        return elements.shuffleInPlace()
    }
    /// Shuffles this collection in place
    @discardableResult
    mutating func shuffleInPlace() -> Self  {
        indices.forEach {
            let subSequence = self[$0...$0]
            let index = indices.randomElement()!
            replaceSubrange($0...$0, with: self[index...index])
            replaceSubrange(index...index, with: subSequence)
        }
        return self
    }
    func choose(_ n: Int) -> SubSequence { return shuffled.prefix(n) }
}

let words = ["python", "jumble", "easy", "difficult", "answer", "xylophone"]

let randomWordShuffled = words.randomElement()?.shuffled ?? "" // "jmeblu"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
2

You want to shuffle the contents of a String.

Easiest way is:

  1. Convert the string to an array: var a = Array(selectedWord)
  2. Use info from this answer to shuffle that array
  3. Convert the array back into a string: let shuffledString = String(a)

So if you pick the mutating shuffle algorithm:

extension Array {
    mutating func shuffle() {
        for i in 0..<(count - 1) {
            let j = Int(arc4random_uniform(UInt32(count - i))) + i
            guard i != j else { continue}
            swap(&self[i], &self[j])
        }
    }
}

let selectedWord = "Apple"

var a = Array(selectedWord)
a.shuffle()
let shuffledWord = String(a)
// shuffledWord = “pAelp” or similar
Community
  • 1
  • 1
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • hi - I had this same code working in an app, but in xCode 7.1 it throws and error saying "swapping a location with itself is not supported'. Have you seen a fix? – richc Nov 05 '15 at 20:43
  • Yeah they added a slightly pedantic assert in a recent release. I've added a guard that should avoid hitting it. – Airspeed Velocity Nov 06 '15 at 14:51
2
func scramble(word: String) -> String {
    var chars = Array(word.characters)
    var result = ""

    while chars.count > 0 {
        let index = Int(arc4random_uniform(UInt32(chars.count - 1)))
        chars[index].writeTo(&result)
        chars.removeAtIndex(index)
    }

    return result
}

The Character struct, via word.characters in the above code, has the functionality to writeTo any OutputStreamType, including String objects. So after you write a randomly selected Character to your resulting string, simply remove it by its index and let the loop continue until there are no more characters left.

  • Thanks--I like it but there is a mistake with this that makes it always keep the last digit the same. To fix, remove the " - 1" after chars.count. arc4random_uniform already returns a number less than the upper bound so subtracting one is unnecessary – garafajon Apr 29 '17 at 22:37
2

Here is a solution:

var myString = "abcdefg"
let shuffledString = String(Array(myString).shuffled())

Explanation:

  1. Convert myString into an array of characters
  2. Shuffle the Array
  3. Convert the Array back into a String
shim
  • 9,289
  • 12
  • 69
  • 108
reg
  • 21
  • 1
1

There are many different algorithms you could use to shuffle a word, but here's one I've written in the same vein/using similar code as your current algorithm which repeatedly selects and removes a random character from your original string to add to the new string:

//this is my array/word bank
var words = ["Apple", "Orange", "Pear"]

//this selects a random word in the array
var selectedWord = words[Int(arc4random_uniform(UInt32(words.count)))]

// The string that will eventually hold the shuffled word
var shuffledWord:String = ""

// Loop until the "selectedWord" string is empty  
while countElements(selectedWord) > 0 {

    // Get the random index
    var length = countElements(selectedWord)
    var position = Int(arc4random_uniform(UInt32(length)))

    // Get the character at that random index
    var subString = selectedWord[advance(selectedWord.startIndex, position)]
    // Add the character to the shuffledWord string
    shuffledWord.append(subString)
    // Remove the character from the original selectedWord string
    selectedWord.removeAtIndex(advance(selectedWord.startIndex, position))
}

println("shuffled word: \(shuffledWord)")
Lyndsey Scott
  • 37,080
  • 10
  • 92
  • 128