Guest User

Untitled

a guest
Jul 1st, 2018
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
F# 5.25 KB | None | 0 0
  1. open System
  2. open System.Collections.Generic
  3. ///Чашка с обхемом и количеством налитой воды
  4. type Cap = {x: int; v: int;}
  5.             override x.ToString() = x.ToString("емкость")
  6.             member x.ToString(capName) = String.Format("{0} объемом {1}л",capName,x.v)
  7.             member x.ToFullString() = String.Format("{0}л в емкости объемом {1}л", x.x,x.v)  
  8. ///Сотояние двух чашем в месте с cool story о том, как они дошли до такого
  9. type CapsState = {caps: Cap * Cap; history: string list}
  10.  
  11. ///Освободить чашку!!!
  12. let emptyChanger {caps=(cap1,cap2);history=h} =
  13.     let empty c = {c with x=0}
  14.     {caps=empty cap1, cap2; history=String.Format("Опустошить {0}",cap1)::h}
  15. ///Наполчнить чарку!!!
  16. let fillChanger {caps=(cap1,cap2);history=h} =
  17.     let fill c = {c with x=c.v}
  18.     {caps=fill cap1, cap2; history= String.Format("Заполнить {0}",cap1)::h}
  19. ///Переливаем из стакана в стакан трезвыми руками так, что ни капли не проливается
  20. let strainChanger {caps=(cap1,cap2);history=h} =
  21.     let strain = function
  22.     | c1, c2 when c1.x+c2.x<=c2.v -> {c1 with x=0}, {c2 with x=c1.x+c2.x}
  23.     | c1, c2                      -> {c1 with x=c1.x-c2.v+c2.x}, {c2 with x=c2.v}
  24.     {caps=strain(cap1,cap2); history=String.Format("Из {0} перелить воду в {1}",
  25.                                                    cap1.ToString("емкости"),cap2)::h}
  26. ///Списко действий, которые можно осуществлять над сосудами                                                                                                    
  27. let changers = [fillChanger; strainChanger; emptyChanger]
  28.  
  29. ///Это всмопогательные активные патерны, должны быть с станадратной либе,
  30. ///но авторы F# считают, что flip или там матчить сиквенсы нинужно
  31. let (|SeqEmpty|SeqCons|) (xs: 'a seq) =
  32.    if Seq.isEmpty xs then SeqEmpty
  33.    else SeqCons(Seq.head xs, Seq.skip 1 xs)
  34.  
  35. let find v1 v2 tv =
  36.    ///Расстояние до нужного нам объема
  37.    let distatnce {caps=c1,c2} =  min (abs (c1.x-tv)) (abs (c2.x-tv))
  38.    ///Запоминаем состояние, в котором побывали
  39.    let setVisited visiteds {caps=caps} = Set.add caps visiteds
  40.    ///Проверяем посящили ли мы состоянние, не забывая, что от перемены мест блабла
  41.    let isVisited visiteds {caps=c1,c2} = Set.contains (c1,c2) visiteds ||
  42.                                          Set.contains (c2,c1) visiteds
  43.    ///Добавляем новые состояния в списоск неповященным
  44.    let addUnvisiteds unvisiteds states =
  45.        Seq.fold(fun u s -> Set.add s u) unvisiteds states
  46.    ///Получаем следующее состояние, которое надо посетить
  47.    ///Для этого группируем состояния по расстоянию до "цели"
  48.    ///Выбираем наименьшее, потом выбираем состояние с самой короткой историей
  49.    let getUnvisited unvisiteds =  
  50.        let unv = unvisiteds |> Seq.groupBy(distatnce) |> Seq.head |> snd
  51.                             |> Seq.sortBy(fun s ->List.length s.history)
  52.                             |> Seq.head
  53.        unv, Set.remove unv unvisiteds
  54.    ///генерируем состояния, в которые можно перейти из текущего
  55.    ///исклюяаем дубликаты и уже посещенные, сортируем по расстоянию
  56.    let getChanges visiteds state =
  57.        let {caps=cap1,cap2} = state
  58.        let revState = {state with caps = cap2,cap1}
  59.        seq{ for s in List.map(fun f -> f state) changers -> s;
  60.             for s in List.map(fun f -> f revState) changers -> s}
  61.        |> Seq.distinctBy(fun s->s.caps)
  62.        |> Seq.filter(isVisited visiteds>>not)
  63.        |> Seq.sortBy(distatnce)
  64.    ///ДАЙ НАЙДЕТ ИЩУЩИЙ!
  65.    let rec find' state visiteds unvisiteds =
  66.         let {caps=c1,c2} = state
  67.         let visiteds = (setVisited visiteds state)
  68.         match distatnce state, (addUnvisiteds unvisiteds (getChanges visiteds state))  with
  69.         | 0, _             -> Some(state) //нашли - ну ок
  70.         | n, SeqEmpty      -> None        //не нашли - ну ок, чо
  71.         | n, unvisiteds    -> let s, u = getUnvisited unvisiteds in find' s visiteds u //ищем дальше
  72.    find' {caps={x=0;v=v1},{x=0;v=v2};history =[]} Set.empty Set.empty
  73.  
  74. match find 5 8 2 with
  75. | None         -> Console.WriteLine("Поиск не дал результатов")
  76. | Some(result) -> result.history |> List.rev |> List.iter (printfn "%s")
  77.                   Console.WriteLine("Найдено состояние \n{0}\n{1}",
  78.                                     (fst result.caps).ToFullString(),
  79.                                     (snd result.caps).ToFullString())
  80.                   Console.WriteLine("Profit!!!")
Add Comment
Please, Sign In to add comment