Bulls and Cows


Task

Create a four digit random number from the digits   1   to   9,   without duplication.

The program should:

   ask for guesses to this number
   reject guesses that are malformed
   print the score for the guess


The score is computed as:

 The player wins if the guess is the same as the randomly chosen number, and the program ends.
 A score of one bull is accumulated for each digit in the guess that equals the corresponding digit in the randomly chosen initial number.
 A score of one cow is accumulated for each digit in the guess that also appears in the randomly chosen number, but in the wrong position.


Related tasks

   Bulls and cows/Player
   Guess the number
   Guess the number/With Feedback
   Mastermind


import Foundation
 
func generateRandomNumArray(numDigits: Int = 4) -> [Int] {
  guard numDigits > 0 else {
    return []
  }
 
  let needed =  min(9, numDigits)
  var nums = Set<Int>()
 
  repeat {
    nums.insert(.random(in: 1...9))
  } while nums.count != needed
 
  return Array(nums)
}
 
func parseGuess(_ guess: String) -> [Int]? {
  guard guess.count == 4 else {
    return nil
  }
 
  let guessArray = guess.map(String.init).map(Int.init).compactMap({ $0 })
 
  guard Set(guessArray).count == 4 else {
    return nil
  }
 
  return guessArray
}
 
while true {
  let num = generateRandomNumArray()
  var bulls = 0
  var cows = 0
 
  print("Please enter a 4 digit number with digits between 1-9, no repetitions: ")
 
  guard let guessStr = readLine(strippingNewline: true), let guess = parseGuess(guessStr) else {
    print("Invalid input")
    continue
  }
 
  for (guess, actual) in zip(guess, num) {
    if guess == actual {
      bulls += 1
    } else if num.contains(guess) {
      cows += 1
    }
  }
 
  print("Actual number: \(num.map(String.init).joined())")
  print("Your score: \(bulls) bulls and \(cows) cows\n")
  print("Would you like to play again? (y): ")
 
  guard readLine(strippingNewline: true)!.lowercased() == "y" else {
    exit(0)
  }
}