bulls_and_cows_player.sf 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Bulls_and_cows/Player#Sidef
  4. #
  5. # Build a list of all possible solutions. The regular expression weeds
  6. # out numbers containing zeroes or repeated digits.
  7. var candidates = (1234..9876 -> grep {|n| !("#{n}" =~ /0 | (\d) .*? \1 /x) }.map{.digits});
  8. # Repeatedly prompt for input until the user supplies a reasonable score.
  9. # The regex validates the user's input and then returns two numbers.
  10. func read_score(guess) {
  11. loop {
  12. "My guess: %s (from %d possibilities)\n" \
  13. -> printf(guess.join, candidates.len);
  14. if (var m = (Sys.scanln("bulls cows: ") =~ /^\h*(\d)\h*(\d)\h*$/)) {
  15. var (bulls, cows) = m.cap.map{.to_i}...;
  16. bulls+cows <= 4 && return(bulls, cows);
  17. }
  18. say "Please specify the number of bulls and the number of cows";
  19. }
  20. }
  21. func score_correct(a, b, bulls, cows) {
  22. var (exact, loose) = (0, 0);
  23. for i in ^4 {
  24. a[i] == b[i] ? ++exact
  25. : (a[i]~~b && ++loose)
  26. }
  27. (bulls == exact) && (cows == loose)
  28. }
  29. # Pick a number, display it, get the score, and discard candidates
  30. # that don't match the score:
  31. loop {
  32. var guess = candidates.pick;
  33. var (bulls, cows) = read_score(guess);
  34. candidates.grep!{|n| score_correct(n, guess, bulls, cows) }
  35. candidates.len > 1 || break
  36. }
  37. # Print the secret number or the error message
  38. (
  39. candidates.len == 1 ? ("Your secret number is: %d" % candidates[0].join)
  40. : ("I think you made a mistake with your scoring")
  41. )->say