逐渐随机显示字符串

时间:2019-03-23 21:46:41

标签: ios swift iteration

我目前正在开发一个简单的程序,以便在两次迭代中逐渐且随机地可视化字符串。现在,我已经设法获得了第一次迭代,但是我不确定如何进行第二次迭代。如果有人可以提供任何示例或建议,我将不胜感激。我的代码如下:

let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45

var n = s.filter({ $0 != " " }).count  // # of non-space characters
var m = lrint(factor * Double(n))      // # of characters to display

let t = String(s.map { c -> Character in
        if c == " " {
        // Preserve space
        return " "
    } else if Int.random(in: 0..<n) < m {
        // Replace
        m -= 1
        n -= 1
        return c
    } else {
        // Keep
        n -= 1
        return "_"
    }
})

print(t)  // h_l__ _l_______d

为澄清起见,我想在第二次迭代中使用factor2打印一些内容,这些内容在t顶部随机添加字母,看起来像这样的h_l_o pl_g _____ d。

2 个答案:

答案 0 :(得分:1)

替换字符

@MartinR 的代码开始,您应该记住已被替换的索引。因此,我将略微更改替换字符的代码:

let s = "Hello playground"
let factor = 0.25
let factor2 = 0.45

var n = s.filter({ $0 != " " }).count  // # of non-space characters
let nonSpaces = n
var m = lrint(factor * Double(n))      // # of characters to display

var indices = Array(s.indices)

var t = ""

for i in s.indices {
    let c = s[i]
    if c == " " {
        // Preserve space
        t.append(" ")
        indices.removeAll(where: { $0 == i })
    } else if Int.random(in: 0..<n) < m {
        // Keep
        m -= 1
        n -= 1
        t.append(c)
        indices.removeAll(where: { $0 == i })
    } else {
        // Replace
        n -= 1
        t.append("_")
    }
}

print(t)   //For example: _e___ ______ou_d

显示角色

为此,我们应该计算要显示的字符数:

m = lrint((factor2 - factor) * Double(nonSpaces))

要选择随机显示的三个索引,我们先洗牌indices,然后替换m第一个索引:

indices.shuffle()
var u = t
for i in 0..<m {
    let index = indices[i]
    u.replaceSubrange(index..<u.index(after: index), with: String(s[index]))
}
indices.removeSubrange(0..<m)

print(u)   //For example: _e__o _l__g_ou_d

答案 1 :(得分:0)

我写了StringRevealer结构,可以为您处理所有揭示逻辑:

/// Hide all unicode letter characters as `_` symbol.
struct StringRevealer {

    /// We need mapping between index of string character and his position in state array.
    /// This struct represent one such record
    private struct Symbol: Hashable {
        let index: String.Index
        let position: Int
    }

    private let originalString: String
    private var currentState: [Character]
    private let charactersCount: Int
    private var revealed: Int
    var revealedPercent: Double {
        return Double(revealed) / Double(charactersCount)
    }
    private var unrevealedSymbols: Set<Symbol>

    init(_ text: String) {
        originalString = text
        var state: [Character] = []
        var symbols: [Symbol] = []
        var count = 0
        var index = originalString.startIndex
        var i = 0
        while index != originalString.endIndex {
            let char = originalString[index]
            if CharacterSet.letters.contains(char.unicodeScalars.first!) {
                state.append("_")
                symbols.append(Symbol(index: index, position: i))
                count += 1
            } else {
                state.append(char)
            }
            index = originalString.index(after: index)
            i += 1
        }
        currentState = state
        charactersCount = count
        revealed = 0
        unrevealedSymbols = Set(symbols)
    }

    /// Current state of text. O(n) conplexity
    func text() -> String {
        return currentState.reduce(into: "") { $0.append($1) }
    }

    /// Reveal one random symbol in string
    mutating func reveal() {
        guard let symbol = unrevealedSymbols.randomElement() else { return }
        unrevealedSymbols.remove(symbol)
        currentState[symbol.position] = originalString[symbol.index]
        revealed += 1
    }

    /// Reveal random symbols on string until `revealedPercent` > `percent`
    mutating func reveal(until percent: Double) {
        guard percent <= 1 else { return }
        while revealedPercent < percent {
            reveal()
        }
    }
}

var revealer = StringRevealer("Hello товарищ! ")
print(revealer.text())
print(revealer.revealedPercent)
for percent in [0.25, 0.45, 0.8] {
    revealer.reveal(until: percent)
    print(revealer.text())
    print(revealer.revealedPercent)
}

它在内部使用CharacterSet.letters,因此应支持大多数语言,可以忽略表情符号和非字母字符。