在F#中我试图在满足条件的情况下删除集合中的出现,但是它并不是真正按照我希望的方式工作。
答案 0 :(得分:4)
从集合中删除元素的技巧是函数Set.filter
,它将函数作为参数 - filter
将函数的每个值提供给函数,并将其添加到函数中如果函数返回true
,则为新集。示例实现可能是:
let filter f (original : Set<'T>) =
set [ for value in original do if f value then yield value ]
,其类型为filter : ('T -> bool) -> Set<'T> -> Set<'T>
。使用它的一个例子是
filter (fun x -> x % 2 = 0) (set [ 1; 2; 3; 4; 5 ])
这会过滤偶数的集合,因此返回值为set [ 2; 4 ]
。
我不完全确定你究竟遇到了什么问题,但这里有一个使用Knuth算法的游戏Mastermind的解决方案,虽然是随机启动猜测,而不是他选择的“1122”。
我认为这是一个非常好的练习,尽管写checkGuess
函数对我来说是最难的部分!
您可以通过运行函数playMastermind ()
在F#interactive中打开它来运行测试,这将显示其猜测。
/// The colours that pegs are allowed to be.
type Peg = Blue | Red | Green | Yellow | Purple | Brown
/// A shared instance of the System.Random () class for all the random number
/// generators.
let private rnd = new System.Random ()
/// Make a random set of four peg colours.
let randomGuess () =
let randomPeg () =
match rnd.Next(1, 6) with
| 1 -> Blue
| 2 -> Red
| 3 -> Green
| 4 -> Yellow
| 5 -> Purple
| 6 -> Brown
| _ -> failwith "Random number generation failed."
[ randomPeg (); randomPeg (); randomPeg (); randomPeg () ]
/// Iterate over the colours to make all of the possible combinations.
let allPossibles =
let colours = [ Blue; Red; Green; Yellow; Purple; Brown]
set [ for a in colours do for b in colours do for c in colours do for d in colours -> [ a; b; c; d ] ]
/// Get the number of white and black pegs when comparing solution to guess.
let checkGuess solution guess =
/// Create a map of (colour -> count).
let toMap = List.countBy id >> Map.ofList
/// Compute how many pegs' colours are shared in the guesses.
let mapIntersect map1 map2 =
let overlap peg count =
match Map.tryFind peg map2 with
| None -> 0
| Some num -> min num count
Map.fold (fun acc peg count -> acc + overlap peg count) 0 map1
/// Simply compare to see if each peg is in the correct place.
let blacks = List.map2 (fun x y -> if x = y then 1 else 0) solution guess |> List.sum
// The number of pegs of the right colour but the wrong location is the
// same as the total number of pegs of the right colour subtract the ones
// that are also in the right place.
let whites = mapIntersect (toMap solution) (toMap guess) - blacks
whites, blacks
/// Get a random element of a set.
let randomSetElement set =
let arr = Set.toArray set
arr.[rnd.Next (Array.length arr)]
let playMastermind () =
// This creates a closure so we can check our guess against the solution,
// without storing the actual value of the solution.
let checkAnswer = checkGuess (randomGuess ())
let rec loop turnCount remaining =
if Set.count remaining = 1 then
let answer = Set.maxElement remaining
printfn "The answer is %A, which I calculated in %d turns." answer (turnCount - 1)
else
let guess = randomSetElement remaining
let (whites, blacks) = checkAnswer guess
printfn "On turn %d I guessed %A, which gave %d white pins and %d black pins." turnCount guess whites blacks
/// Remove all possibilities from the solution that wouldn't give the
/// same numbers of white and black pins and continue.
loop (turnCount + 1) (Set.filter (fun possible -> (whites, blacks) = checkGuess possible guess) remaining)
// Play the game!
loop 1 allPossibles
答案 1 :(得分:1)
我将此作为评论,但它太长了,所以它需要成为答案,即使它不是完整的答案你的问题。
现在,您的代码存在一个问题:
for candidate in candidateSet do
let scString = candidate.ToString()
let mutable secretList = []
for i = 0 to 3 do
let digit = (int scString.[i])-(int '0')
secretList <- secretList @ [digit]
let tempCode = List.map (fun x -> numberToCodeColorPlus (x)) secretList
//Validate works and returns a peg set (b,w)..e.g. (0,0)
let secretCodePegs = validate guess tempCode
if secretCodePegs <> guessPegs then
candidateSet <- Set.remove candidate candidateSet
与Python一样,F#使用缩进来表示块。因此let secretCodePegs = validate guess tempCode
行 <{1}}循环,而不是for
循环内部,就像您明确指出的那样。就F#而言,其后面的for
行是 new 块的一部分,而不再是if secretCodePegs <> guessPegs then
循环的一部分(因为{ {1}}行结束了for
循环)。您需要做的就是将let secretCodePegs = ...
行缩进一级,您的代码才能正常工作。换句话说,部分应该是这样的:
for