Как мне написать классическую игру хай / лоу на F #? - PullRequest
7 голосов
/ 10 ноября 2010

Я читал на функциональных языках, и мне было интересно, как бы я реализовал «попытки» на чистом функциональном языке. Поэтому я решил попробовать сделать это в F #

Но я не мог получить половину основ. Я не мог понять, как использовать случайное число, как использовать return / continue (сначала я подумал, что я делаю несколько выражений, если неправильно, но кажется, что я делал это правильно), и я не мог понять, как напечатать число в F #, поэтому я сделал это в C #.

Более сложные проблемы - это выходной параметр в tryparse, и я до сих пор не уверен, как реализовать tries без использования изменяемой переменной. Может быть, некоторые из вас, ребята, могут сказать мне, как я могу правильно реализовать это

C # код, который я должен был сделать на прошлой неделе

using System;

namespace CS_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var tries = 0;
            var answer = new Random().Next(1, 100);
            Console.WriteLine("Guess the number between 1 and 100");
            while (true)
            {
                var v = Console.ReadLine();
                if (v == "q")
                {
                    Console.WriteLine("you have quit");
                    return;
                }
                int n;
                var b = Int32.TryParse(v, out n);
                if (b == false)
                {
                    Console.WriteLine("This is not a number");
                    continue;
                }
                tries++;
                if (n == answer)
                {
                    Console.WriteLine("Correct! You win!");
                    break;
                }
                else if (n < answer)
                    Console.WriteLine("Guess higher");
                else if (n > answer)
                    Console.WriteLine("Guess lower");
            }
            Console.WriteLine("You guess {0} times", tries);
            Console.WriteLine("Press enter to exist");
            Console.ReadLine();
        }
    }
}

Очень сломанный и неправильный код F #

open System;

let main() =
    let tries = 0;
    let answer = (new Random()).Next 1, 100
    printfn "Guess the number between 1 and 100"
    let dummyWhileTrue() =
        let v = Console.ReadLine()
        if v = "q" then
            printfn ("you have quit")
            //return
        printfn "blah"
        //let b = Int32.TryParse(v, out n)
        let b = true;
        let n = 3
        if b = false then
            printfn ("This is not a number")
            //continue;
        //tries++
        (*
        if n = answer then
            printfn ("Correct! You win!")
            //break;
        elif n < answer then
            printfn ("Guess higher")
        elif n>answer then
            printfn ("Guess lower")
        *)
    dummyWhileTrue()
    (Console.WriteLine("You guess {0} times", tries))
    printfn ("Press enter to exist")
    Console.ReadLine()
main()

Ответы [ 4 ]

6 голосов
/ 10 ноября 2010

Вот мое мнение, просто для удовольствия:

open System

let main() = 
    let answer = (new Random()).Next(1, 100)
    printfn "Guess the number between 1 and 100" 
    let rec TryLoop(tries) = 
        let doneWith(t) = t
        let notDoneWith(s, t) = printfn s; TryLoop(t) 
        match Console.ReadLine() with
        | "q" -> doneWith 0
        | s -> 
            match Int32.TryParse(s) with
            | true, v when v = answer -> doneWith(tries)
            | true, v when v < answer -> notDoneWith("Guess higher", tries + 1) 
            | true, v when v > answer -> notDoneWith("Guess lower", tries + 1)
            | _ -> notDoneWith("This is not a number", tries)

    match TryLoop(1) with
        | 0 -> printfn "You quit, loser!"
        | tries -> printfn "Correct! You win!\nYou guessed %d times" tries

    printfn "Hit enter to exit"
    Console.ReadLine()  |> ignore
main() 

На заметку:

  • Сопоставление с шаблоном красивее, лаконичнее и, я полагаю, более идиоматично, чемnested ifs
  • Использовал стиль возврата кортежа TryParse, предложенный Брайаном
  • Переименованный dummyWhileTrue в TryLoop, казался более информативным
  • Создал две внутренние функции doneWith и notDoneWith, (по чисто эстетическим соображениям)
6 голосов
/ 10 ноября 2010

Добро пожаловать в F #!

Вот рабочая программа;пояснение приведено ниже.

open System

let main() = 
    let answer = (new Random()).Next(1, 100)
    printfn "Guess the number between 1 and 100" 
    let rec dummyWhileTrue(tries) = 
        let v = Console.ReadLine() 
        if v = "q" then 
            printfn "you have quit"
            0
        else
            printfn "blah" 
            let mutable n = 0
            let b = Int32.TryParse(v, &n) 
            if b = false then 
                printfn "This is not a number"
                dummyWhileTrue(tries)
            elif n = answer then 
                printfn "Correct! You win!"
                tries
            elif n < answer then 
                printfn "Guess higher"
                dummyWhileTrue(tries+1) 
            else // n>answer
                printfn "Guess lower"
                dummyWhileTrue(tries+1) 
    let tries = dummyWhileTrue(1) 
    printfn "You guess %d times" tries
    printfn "Press enter to exit"
    Console.ReadLine()  |> ignore
main() 

Несколько вещей ...

Если вы вызываете методы с несколькими аргументами (например, Random.Next), используйте скобки вокруг аргументов (* 1009)*).

Вы, похоже, работали над рекурсивной функцией (dummyWhileTrue), а не над циклом while;цикл while тоже сработает, но я оставил его на вашем месте.Обратите внимание, что в F # нет break или continue, поэтому вы должны быть немного более структурированы с материалом if внутри.

Я изменил ваш Console.WriteLine на printfnчтобы показать, как вызывать его с аргументом.

Я показал способ вызова TryParse, который больше всего похож на C #.Сначала объявите вашу переменную (сделайте ее изменяемой, поскольку TryParse будет записывать в это местоположение), а затем используйте &n в качестве аргумента (в этом контексте &n походит на ref n или out n в C #),В качестве альтернативы, в F # вы можете сделать так:

let b, n = Int32.TryParse(v)

, где F # позволяет вам опустить trailing-out-параметры и вместо этого возвращает их значение в конце кортежа;это всего лишь синтаксическое удобство.

Console.ReadLine возвращает строку, которая вам не нужна в конце программы, поэтому передайте ее в функцию ignore, чтобы сбросить значение (и получитьизбавиться от предупреждения о неиспользованном строковом значении).

5 голосов
/ 10 ноября 2010

Я поднял соответствие основного шаблона с Evaluate в решении @ Huusom, но выбрал рекурсивный цикл и аккумулятор вместо (очень крутого) распознающего объединения @ Hussom и применения Seq.unfold для очень компактного решения.

open System
let guessLoop answer = 
    let rec loop tries =
        let guess = Console.ReadLine()
        match Int32.TryParse(guess) with
        | true, v when v < answer -> printfn "Guess higher." ; loop (tries+1)
        | true, v when v > answer -> printfn "Guess lower." ; loop (tries+1)
        | true, v -> printfn "You won." ; tries+1
        | false, _ when guess = "q" -> printfn "You quit." ; tries
        | false, _ -> printfn "Not a number." ; loop tries
    loop 0

let main() =
    printfn "Guess a number between 1 and 100."
    printfn "You guessed %i times" (guessLoop ((Random()).Next(1, 100)))
3 голосов
/ 10 ноября 2010

Также для удовольствия, если:

open System

type Result =
    | Match
    | Higher
    | Lower
    | Quit
    | NaN

let Evaluate answer guess =
    match Int32.TryParse(guess) with
    | true, v when v < answer -> Higher
    | true, v when v > answer -> Lower
    | true, v -> Match
    | false, _ when guess = "q" -> Quit
    | false, _ -> NaN

let Ask answer =
    match Evaluate answer (Console.ReadLine()) with
    | Match -> 
        printfn "You won."
        None
    | Higher -> 
        printfn "Guess higher."
        Some (Higher, answer)
    | Lower -> 
        printfn "Guess lower."
        Some (Lower, answer)
    | Quit -> 
        printfn "You quit."
        None
    | NaN ->
        printfn "This is not a number."
        Some (NaN, answer)

let main () = 
    printfn "Guess a number between 1 and 100."
    let guesses = Seq.unfold Ask ((Random()).Next(1, 100))
    printfn "You guessed %i times" (Seq.length guesses)

let _ = main()

Я использую перечисление для состояния и Seq.unfold для ввода, чтобы найти результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...