воскресенье, 29 августа 2010 г.

"Кости" в консоли на F#

небольшая "игрушка" написанная на F# с применением ООП...
написанная правда фигово с точки зрения того же ООП:)

смысл - посмотреть, как юзаются классы с F#)

module BoneGame

open System
open System.Collections.Generic

#light

type UserInterface () =
    member x.Roll : bool =
        printfn "Вы будете бросать кубик?"
        x.QuestYN

    member x.PrintState (data : list) : unit = 
        for e in data do
            printfn "%s" <| e

    member x.QuestYN : bool =
        printf "Ваше решениие(Y или N): "
        match Console.ReadLine() with
            | "Y" | "y" -> true
            | "N" | "n" -> false
            | _ -> x.QuestYN 

    member x.Win : unit =
        printfn "Поздравляем, Вы выйграли!!!"
        Console.ReadKey () |> ignore

    member x.Louse (name : string) : unit =
        printfn "Вы проиграли! Выйграл %s." name
        Console.ReadKey () |> ignore

    member x.GeneratePlayerList : list =
        printf "Введите имя игрока: "
        let name = Console.ReadLine()
        printfn "Будут ещё игроки?"
        if x.QuestYN then name :: x.GeneratePlayerList
        else [name]

type Player (name   : string,
             score  : int,
             UI     : UserInterface) =
    let name    = name
    let ui      = UI
    let mutable score = score

    member x.Name   with get () = name
    member x.UI     with get () = ui
    member x.Score  with get () = score and set v = score <- v + score

    member x.Roll : bool = ui.Roll

type Game () =
    let intrf = UserInterface ()
    let mutable Players = new Queue ()

    do 
        let p_name = intrf.GeneratePlayerList
        for e in p_name do
            Players.Enqueue ( new Player (e, 0, intrf))

    let max_score = 100

    let bone_roll = (new Random (int(DateTime.Now.Ticks))).Next(1, 6)

    member x.Start : unit =
        let mutable end_flag = true
        while end_flag do
            // выбираем игрока, чья очередь бросать кости
            let current_player = Players.Dequeue ()
            let mutable sum = 0
            let mutable flag = true

            Console.Clear () // !!!!!!!!!!!!!!
            // выводим данные о игровой ситуации
            current_player.UI.PrintState ["Бросает " + current_player.Name;
                                          "Очков у игрока: " + current_player.Score.ToString ();
                                          "--------------------";]
            for e in Players do
                current_player.UI.PrintState ["Противник " + e.Name;
                                              "Очков " + e.Score.ToString ()]
            current_player.UI.PrintState ["--------------------"]

            Console.ReadKey () |> ignore
            Console.Clear ()

            // бросок игрока
            current_player.UI.PrintState ["Будете бросать?"]
            while flag && current_player.Roll do
                let r = (new Random (int(DateTime.Now.Ticks))).Next(1, 6)
                current_player.UI.PrintState ["Вы выбросили " + r.ToString () + " очков"]
                if r <> 1 then 
                    sum <- sum + r
                    current_player.UI.PrintState ["За ход вы набрали " + sum.ToString () + " очков"]
                else 
                    flag <- false
                    sum  <- 0
                    current_player.UI.PrintState ["К сожалению ваши очки, набранные за ход обнуляются"]
                    Console.ReadKey () |> ignore
            current_player.Score <- sum

            // обрабатываем результаты броска
            if current_player.Score < max_score then
                Players.Enqueue (current_player)    // продолжаем игру
            else
                current_player.UI.Win |> ignore
                for e in Players do
                    e.UI.Louse |> ignore
                end_flag <- false

[]
let main _ = 
    printfn "Приветствуем вас в игре Кости!"

    let G = new Game ()
    G.Start
    Console.ReadKey() |> ignore
    0

пятница, 27 августа 2010 г.

Циклы на F#

Сейчас попытался реализовать довольно тривиальный цикл, который на C++ выглядел бы следующим образом:

while(true)
{
    string buf = "";
    cout << "write string(Y/N): ";
    cin >> buf;
    if(buf == "Y") return true;
    if(buf == "N") return false;
}

довольно тривиальная весчь, заставляющая ввести либо Y, либо N.
но вот на F# возникли некоторые проблемы(предположительно из-за того, что ключевое слово return можно не использовать и юзался #light)

т.е. написать в лоб:

while true do
  printf "write string(Y/N): "
  let Sol = Console.ReadLine()
  if Sol = "Y" then true
  if Sol = "N" then false

не получается, т.к. компилятор начинал ругаться на то, что возвращаемое выражение имеет неправильный тип...

в итоге это было решено следующим образом(в ФП стиле кстати, в императивном стиле я решения не нашёл удовлетворительного(два match и лишняя переменная не в счёт)):

type ... =
  ...
  member x.entr = 
        printfn "Enter your solution(Y/N): "
        match Console.ReadLine() with
            | "Y" -> true
            | "N" -> false
            | _ -> x.entr
  ...
  interface ... with
    member x.roll (flag : bool, data : IRollData) = 
            intrf.print data.DataList
            if flag = true then x.entr
            else false

хотя не думаю, что это лучший выход... скорее всего я как-то не так понял работу цикла while-do

четверг, 26 августа 2010 г.

Тест отображение кода

type test = 
    { A : int; B : int}
    member this.copyB dB = { this with B = this.B + dB}

ну вот, теперь я знаю, что для корректного отображения кода программ нужно использовать тег pre:)

значит скоро буду постить примеры кода на F#, раз уж я им занялся)

среда, 18 августа 2010 г.

F#, первое знакомство

F# - это функциональный язык разработанный в M$ под платформу .Net, близкий родственник Haskell.

Первые ощущения от языка - странно.
Оч. похоже на Haskell и Python на первый взгляд. Сразу бросается в глаза использование отступов для различения блоков кода, но это есть гуд кстати(есть и в питоне и в хаскеле).
Потом... функцию main можно определить следующим образом:
let main ( _ ) =
    ...
ну или более стандартно(если аргументы имеют для нас значение):
let main ( args : string[] ) =
    ...

_ - явное использование паттерн матчинга(ура, классная весч), в хаскеле оч. часто ей пользуешься)
= - опять аналогия с хаскель...

это всё хорошо, мне нравится...
но вот много строчные комментарии вида (* много\nтысч\nбукаф *) убивают... хочется стандартных, для C#, /* **/ с автопереносом и автодобавлением звёздочек...

а да, чуть не забыл... вместо привычного main, как точки входа в программу, можно использовать к примеру MaIInbl...
ибо дело в том, что точка входа опр. с помощью добавления перед функцией [%EntryPoint%]*
, которая будет точкой входа.

*вместо [% следует ставить [<, а вместо %] - >]

Обида забывает боль

Я, продолжавший путь, когда за мной вдогонку,
Эскорты чёрных рыб пускались из глубин,
И загонял июль в пылавшую воронку
Ультрамарин небес ударами дубин...


Артюр Рембо
 

среда, 11 августа 2010 г.

Нян-нян:)

CodePlex, Mercurial и переезды...

ммм... с чего бы начать... начала то особо и нету))

Пожалуй следует начать с того, что я доделал первый вариант кода для объединения динамических систем и залил его на гиториус(http://gitorious.org/fds/association_of_dynamical_systems).

Там вроде как бы всё более менее работает... но вот получилось всё достаточно криво по нескольким причинам:

  • Я плохо представлял себе структуру, которую в итоге должен построить, да и вообще с трудом представлял себе, как это всё должно выглядеть с точки зрения программирования.
  • Я плохо знал C# (я и сейчас не особо то его знаю) и его возможности. Сейчас с этим чуточку получше.
В общем говоря начало переписывания этого кода для получения вменяемой библиотеки классов и интерфейсов было делом времени. Ну и я решил начать потихоньку.

А так как я стал периодически получать от гугла ссылки на Open Source проекты выложенные на CodePlex, то было решено использовать в этот раз именно его.
Немаловажным фактором тут играет и то, что для Mercurial(который юзается на CodePlex) существует плагин VisualHG для TortoiseHG интегрирующийся в VS.

Так что теперь мой код по ДС публикуется тут(лицензия LGPL, ибо не жадный я:).