{"id":467886,"date":"2025-07-20T21:45:52","date_gmt":"2025-07-20T21:45:52","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=467886"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=467886","title":{"rendered":"<span>\u0428\u0435\u0441\u0442\u0438\u0434\u0435\u0441\u044f\u0442\u0438\u043b\u0435\u0442\u043d\u0438\u0439 \u0437\u0430\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u0439 \u0438 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u0430\u044f \u043a\u0440\u044b\u0441\u0430. F# \u043d\u0430 Godot. \u0427\u0430\u0441\u0442\u044c 8. \u0417\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ws\/a1\/bl\/wsa1blbfiq53nqgaktrrkws_sdk.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/ws\/a1\/bl\/wsa1blbfiq53nqgaktrrkws_sdk.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/ws\/a1\/bl\/wsa1blbfiq53nqgaktrrkws_sdk.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041c\u044b \u043a\u043e\u0432\u044b\u0440\u044f\u043b\u0438 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 <code>A*<\/code> \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 <a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/919448\/\" rel=\"noopener noreferrer nofollow\">\u0434\u0432\u0443\u0445 \u0433\u043b\u0430\u0432<\/a> \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0431\u044b\u043b\u0438 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u044b \u043d\u0430 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0438\u0437\u044b\u0441\u043a\u0430\u0445 F#. \u0412 \u044d\u0442\u043e\u0439 \u0433\u043b\u0430\u0432\u0435 \u043c\u044b \u043e\u0442\u0434\u043e\u0445\u043d\u0451\u043c \u043e\u0442 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a \u044d\u0442\u043e\u0442 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043c\u043e\u0433 \u0431\u044b \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0431\u043e\u043b\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<h3>\u041f\u0440\u0438\u043a\u0432\u0435\u043b<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/806145\/\" rel=\"noopener noreferrer nofollow\">An incursion under C#. \u041f\u0440\u043e\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u0435\u043c F# \u0432 Godot<\/a> <\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/904306\/\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>\u0428\u0435\u0441\u0442\u0438\u0434\u0435\u0441\u044f\u0442\u0438\u043b\u0435\u0442\u043d\u0438\u0439 \u0437\u0430\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u0439 \u0438 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u0430\u044f \u043a\u0440\u044b\u0441\u0430. F# \u043d\u0430 Godot<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/846224\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1. \u0412\u0441\u0442\u0440\u0435\u0447\u0430 \u0441 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/850980\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 2. \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/856406\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 3. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b c \u043f\u0435\u0440\u0435\u0441\u0430\u0434\u043a\u0430\u043c\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/904772\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 4. \u0414\u0435\u0444\u043e\u043b\u0442\u044b, option \u0438 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/909536\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 5. \u041e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/917404\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 6. \u041a\u0430\u043a \u0434\u043e\u0431\u044b\u0442\u044c \u043d\u0435\u0447\u0442\u043e<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/919448\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 7. \u041a\u0430\u043a \u0443\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043d\u0435\u0447\u0442\u043e<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/926138\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 8. \u0417\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438<\/a> \/\/ \u043c\u044b \u0437\u0434\u0435\u0441\u044c<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<h3>\u041f\u0443\u0442\u044c \u0424\u041f<\/h3>\n<p>\u0412 <a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/917404\/\" rel=\"noopener noreferrer nofollow\">6 \u0433\u043b\u0430\u0432\u0435<\/a> \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0435 \u043f\u043e\u0438\u0441\u043a\u0430:<\/p>\n<pre><code class=\"fsharp\">let tryFindPath mapSize isObstacle start goal =     if not ^ inMap mapSize goal then Result.Error OutOfBounds     elif isObstacle goal then Result.Error Obstacle else     let frontier = PriorityStack.singleton 0 start     let cameFrom = Dictionary.singleton start start     let costSoFar = Dictionary.singleton start 0      let rec tryFind () =         match frontier.TryTake () with         | None -&gt; Result.Error Unreachable         | Some (Eq goal) -&gt;             let path = Stack()             path.Push goal             let rec buildPath current =                 if current &lt;&gt; start then                     let current = cameFrom.[current]                     path.Push current                     buildPath current             buildPath goal             Ok {|                 Path = List.ofSeq path                 Cost = costSoFar.[goal]                 Start = start                 Goal = goal                 CostSoFar = costSoFar.AsReadOnly()                 CameFrom = cameFrom.AsReadOnly()                 Frontier = List.ofSeq ^ frontier.AsSeq()             |}         | Some current -&gt;             let newCost = costSoFar.[current] + 1             for next in neighbours mapSize isObstacle current do                 match costSoFar.TryGetValue next with                 | true, oldCost when newCost &gt;= oldCost -&gt; ()                 | _ -&gt;                     costSoFar.[next] &lt;- newCost                     frontier.Put (newCost + heuristic goal next) next                     cameFrom.[next] &lt;- current             tryFind ()     tryFind () <\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043d\u0451\u043c \u043d\u0430\u0434\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e <code>cameFrom : Dictionary&lt;Vector2I, Vector2I&gt;<\/code>. \u041a\u0430\u0436\u0434\u044b\u0439 \u0435\u0451 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 <code>value<\/code> \u0432 <strong>\u0441\u043e\u0441\u0435\u0434\u043d\u044e\u044e<\/strong> \u0442\u043e\u0447\u043a\u0443 <code>key<\/code>. \u042d\u0442\u043e \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u0448\u0430\u0433, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0437 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 (<code>start =&gt; key<\/code>). \u0422\u0430\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0451\u0448\u0435\u0432, \u043d\u043e \u043d\u0435\u0443\u0434\u043e\u0431\u0435\u043d \u0442\u0435\u043c, \u0447\u0442\u043e \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043f\u0443\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442. \u0415\u0441\u043b\u0438 \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 <code>cameFrom<\/code> \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043f\u0443\u0449\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430, \u0442\u043e <code>buildPath<\/code> \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0446\u0438\u043a\u043b\u0438\u0442\u044c\u0441\u044f \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u043d\u0435\u0442 \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u044f\u043a\u043e\u0431\u044b \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0417\u0432\u0443\u0447\u0438\u0442 \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u0442\u0440\u0430\u0448\u043d\u043e, \u043d\u043e \u044f \u0442\u0443\u0442 \u043f\u043e\u043a\u043e\u0432\u044b\u0440\u044f\u043b \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043f\u043e\u043b\u0435 \u0435\u0441\u0442\u044c \u0437\u043e\u043d\u044b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a\u0430, \u043a\u043e\u043d\u044e\u0448\u043d\u0438 (\u0432\u043e\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043c\u0438\u043d\u044b), \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u044b \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u0432\u0440\u043e\u0434\u0435 \u043a\u0430\u043a \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438, \u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0441 \u0431\u0430\u0433\u0430\u043c\u0438, \u043d\u0435\u0434\u0440\u0430 <code>cameFrom<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u043d\u0438\u0439 \u043f\u0440\u0438 \u043f\u043e\u0447\u0442\u0438 \u043d\u0443\u043b\u0435\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u0445 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438. \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043e\u0442 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043c\u043e\u0436\u043d\u043e \u0438 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0430.<\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043d\u0430 \u043a\u043e\u0440\u043d\u044e, \u0435\u0441\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0438\u0437 <code>start<\/code> \u0432 <code>key<\/code> \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u0433\u043e <strong>\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439<\/strong> \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041c\u044b \u0442\u0430\u043a\u043e\u0435 \u0443\u0436\u0435 \u0434\u0435\u043b\u0430\u043b\u0438, \u043a\u043e\u0433\u0434\u0430 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u0440\u0430\u0431\u043b\u044f. \u0422\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b <code>Vector2I list<\/code> \u0432\u0438\u0434\u0430 <code>[start; ... ; key]<\/code>. \u041e\u0442\u043a\u0443\u0441\u044b\u0432\u0430\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u0443\u044e \u0433\u043e\u043b\u043e\u0432\u0443 (\u043f\u0435\u0440\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442), \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0443\u0442\u0438 \u0432 \u043e\u0441\u0442\u0430\u0442\u043a\u0435:<\/p>\n<pre><code class=\"fsharp\">match motion with | [] -&gt; ... | next :: remain -&gt; ... <\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u0443\u0442\u0438 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u043d\u0435 \u0437\u0430\u0431\u0438\u0440\u0430\u0442\u044c \u0433\u043e\u043b\u043e\u0432\u0443, \u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043d\u0435\u0446 \u0441\u043f\u0438\u0441\u043a\u0430:<\/p>\n<pre><code>\u043f\u0443\u0442\u044c \u0434\u043e `n + 1` = \u043f\u0443\u0442\u044c \u0434\u043e `n` + \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b `n + 1` <\/code><\/pre>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0434\u043e\u0440\u043e\u0433\u043e \u043d\u0430\u043c \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0432 \u0441\u0438\u043b\u0443 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 <code>'a list<\/code>:<\/p>\n<pre><code class=\"fsharp\">\/\/ \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f `list`: type 'a List =     | Nil     | Cons of (Head : 'a) * (Tail : 'a List) <\/code><\/pre>\n<p><code>list<\/code> \u0443\u043c\u0435\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430 <code>O(1)<\/code> \u00ab\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u00bb \u0438 \u00ab\u0443\u0434\u0430\u043b\u044f\u0442\u044c\u00bb \u0433\u043e\u043b\u043e\u0432\u0443, \u043d\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0441 \u0445\u0432\u043e\u0441\u0442\u043e\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u043a\u0438 \u0432\u0441\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430 <code>O(n)<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0434\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0443\u0442\u044c \u0437\u0430\u0434\u043e\u043c \u043d\u0430\u043f\u0435\u0440\u0451\u0434 (\u0440\u0435\u0447\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e \u0444\u043e\u0440\u043c\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f), \u0442\u043e\u0433\u0434\u0430 <code>key<\/code> \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0443:<\/p>\n<pre><code class=\"fsharp\">paths.[next] &lt;- next :: paths.[current] <\/code><\/pre>\n<p>\u042d\u0442\u043e \u0440\u0430\u0431\u043e\u0447\u0435\u0435, \u044f \u0431\u044b \u0434\u0430\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b, \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u041c\u044b \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u0435\u043c \u043a \u043d\u0435\u043c\u0443 \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u0445, \u0442\u0430\u043a \u0447\u0442\u043e \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0440\u0430\u0442\u044c \u043d\u0430 \u0432\u043e\u043e\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0434\u0438\u044f\u0445 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u0438 \u043f\u0443\u0442\u0438 \u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0438 \u0438\u0445 \u043d\u0430\u0434\u043e \u0440\u0435\u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e. \u0412 \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0439\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u0445 (\u043d\u0435 \u043d\u0430\u0448 \u0441\u043b\u0443\u0447\u0430\u0439) \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0448\u0430\u043d\u0441 \u043e\u0448\u0438\u0431\u0438\u0442\u044c\u0441\u044f \u0432 \u00ab\u0447\u0451\u0442\u043d\u043e\u0441\u0442\u0438\u00bb <code>List.rev<\/code>, \u0432\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 \u0447\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 SCDU \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"fsharp\">\/\/ \u041f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442: type 'a RevList = {     AsReversedList : 'a list  }     with     member this.AsList = List.rev this.AsReversedList     static member create reversedList = { AsReversedList = reversedList }     ...  \/\/ \"\u0423\u043c\u043d\u044b\u0439\" \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c. \/\/ `equality` \u0438 `comparison` \u043e\u0442\u0432\u0430\u043b\u044f\u0442\u0441\u044f, \/\/ \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0445 \u043d\u0430\u0434\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e. type 'a RevListCached = private {     asReversedList : 'a list     asList : 'a list Lazy }     with     member this.AsReversedList = this.asReversedList     member this.AsList = this.asList.Value     static member create reversedList = {         asReversedList = reversedList         asList = lazy(List.rev reversedList)     }     ...  <\/code><\/pre>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a\u0440\u0443\u0447\u0435, \u0435\u0441\u043b\u0438 \u0432\u0437\u044f\u0442\u044c \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0443\u043c\u0435\u044e\u0449\u0443\u044e \u0440\u0430\u0441\u0442\u0438 \u0441 \u043a\u043e\u043d\u0446\u0430. \u0412 \u043f\u0430\u043a\u0435\u0442\u0435 <code>FSharpx.Collections<\/code> \u0435\u0441\u0442\u044c <code>'a PersistentVector<\/code>. \u041e\u043d \u0432\u0435\u0434\u0451\u0442 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u043b\u0438\u043d\u0435\u0439\u043d\u0430\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f, \u043d\u043e \u043f\u043e\u0434 \u0435\u0433\u043e \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043f\u0440\u044f\u0447\u0435\u0442\u0441\u044f \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043c\u0435\u0435\u0442 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0451\u0448\u0435\u0432\u043e:<\/p>\n<ul>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u0432\u043e\u0439 \u043a\u043e\u043d\u0435\u0446 \u2014 <code>Conj<\/code> (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 <code>Cons<\/code>);<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0434\u0451\u0440\u0433\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u2014 <code>Initial, Last<\/code> (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 <code>Head, Tail<\/code>);<\/p>\n<\/li>\n<li>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u00ab\u0438\u0441\u043a\u0430\u0442\u044c\u00bb \u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u0443 \u2014 <code>nth<\/code>\/\u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0442\u043e\u0440 \u0438 <code>update<\/code> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u044f\u0437\u044b\u043a\u043e\u043c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0439, \u0442\u043e \u0432 \u043d\u0430\u0440\u043e\u0434\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043e \u043c\u043d\u0435\u043d\u0438\u0435, \u0447\u0442\u043e <code>list<\/code> \u2014 \u044d\u0442\u043e \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442 <code>Stack<\/code>, \u0430 <code>PersistentVector<\/code> \u2014 \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442 <code>ResizeArray<\/code> (<code>List<\/code> \u0432 C#).<\/p>\n<p><code>'a PersistentVector<\/code> \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f <code>cameFrom<\/code>, \u043d\u043e \u0438 \u0434\u043b\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0435\u0439 <code>costSoFar<\/code>. \u041e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043d\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0435\u0451 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u0435\u043d \u0434\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438, \u0447\u0442\u043e \u043e\u0431\u0435 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0438\u0442\u044c \u0432 \u043e\u0434\u043d\u0443, \u0435\u0441\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 <code>'a<\/code> \u0432\u0437\u044f\u0442\u044c \u0442\u0443\u043f\u043b \u0438\u043b\u0438 \u0440\u0435\u043a\u043e\u0440\u0434:<\/p>\n<pre><code class=\"fsharp\">let tryFindPath mapSize isObstacle start goal =     if not ^ inMap mapSize goal then Result.Error OutOfBounds     elif isObstacle goal then Result.Error Obstacle else     let frontier = PriorityStack.singleton 0 start     \/\/ \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438:     let createStep position cost = {|         Position = position         Cost = cost     |}     let paths =         createStep start 0         |&gt; PersistentVector.singleton         |&gt; Dictionary.singleton start      let rec tryFind () =         match frontier.TryTake () with         | None -&gt; Result.Error Unreachable         | Some (Eq goal) -&gt;             Ok {|                 Path = paths.[goal]                 Cost = paths.[goal].Last.Cost                 Goal = goal                 Start = start                 Paths = paths.AsReadOnly()                 Frontier = List.ofSeq ^ frontier.AsSeq()             |}         | Some current -&gt;             let currentPath = paths.[current]             let newCost = currentPath.Last.Cost + 1             for next in neighbours mapSize isObstacle current do                 match paths.TryGetValue next with                 | true, PersistentVector.Conj (_, old) when newCost &gt;= old.Cost -&gt; ()                 | _ -&gt;                     frontier.Put (newCost + heuristic goal next) next                     paths.[next] &lt;- currentPath.Conj ^ createStep next newCost             tryFind ()     tryFind () <\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0436\u0434\u043e\u043c <code>paths.[key]<\/code> \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f <code>PersistentVector<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"fsharp\">{| Position = start; Cost = 0 |} {| Position = \u0441\u043e\u0441\u0435\u0434 start; Cost = 1 |} ... {| Position = \u0441\u043e\u0441\u0435\u0434 key; Cost = finalCost - 1 |} {| Position = key; Cost = finalCost |} <\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u0442\u043e\u0447\u043a\u0443 \u0441\u0442\u0430\u0440\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0440\u0430\u043d\u044c\u0448\u0435 <code>buildPath<\/code> \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b. \u042d\u0442\u043e \u043d\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 <code>PersistentVector<\/code>, \u0430 \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u041c\u043d\u0435 \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043d\u0430 \u0440\u0443\u043a\u0443, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u0447\u0438\u043d\u0430\u043b <code>paths<\/code> \u0441 <code>singleton<\/code>. \u0415\u0441\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u0432\u0437\u044f\u0442\u044c <code>PersistentVector.empty<\/code>, \u043f\u0443\u0442\u0438 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0443\u0442 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u00ab\u0431\u0435\u0437\u0433\u043e\u043b\u043e\u0432\u0443\u044e\u00bb \u0444\u043e\u0440\u043c\u0443.<\/p>\n<p>\u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0432 \u044d\u0442\u0438\u0445 \u00ab\u043f\u0440\u0430\u0432\u0438\u043b\u0430\u0445 \u0438\u0433\u0440\u044b\u00bb \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u043b\u0435\u0442\u043e\u043a \u0441\u043e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0439 \u043e\u0442 \u043d\u0443\u043b\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 <code>Cost<\/code> \u0437\u0434\u0435\u0441\u044c \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c \u0441\u0432\u043e\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430. <code>Cost<\/code> \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043f\u0443\u0442\u0438, \u0438 \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043a\u0430\u043a <code>persistentVector.Length - 1<\/code>. \u042d\u0442\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u043e\u0438\u0442\u044c <code>O(1)<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a <code>PersistentVector<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u0432\u043e\u044e \u0434\u043b\u0438\u043d\u0443 \u0432 \u0433\u043e\u0442\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0435 (\u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>list<\/code>). \u041e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044f\u0441\u044c \u043d\u0430 \u044d\u0442\u043e\u043c, \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u0440\u0435\u043a\u043e\u0440\u0434\u0430 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 <code>Vector2I<\/code> (<code>Vector2I PersistentVector<\/code>).<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u044f \u0442\u0430\u043a \u043d\u0435 \u0434\u0435\u043b\u0430\u044e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043b\u0430\u043d\u0434\u0448\u0430\u0444\u0442\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0440\u0435\u043a\u043e\u0440\u0434\u0430\u0445 \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 (\u0442. \u0435. \u0434\u0435\u043b\u044c\u0442\u0443) \u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435 \u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0442\u0438\u043f\u0430 \u00ab\u043f\u043e\u043f\u0430\u043b \u0432 \u0437\u043e\u043d\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0432\u0440\u0430\u0433\u0430\u00bb \u0438 \u0442. \u0434.<\/p>\n<p><em>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u043e\u0442\u0432\u0430\u0434\u0438\u0442\u044c \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u0442 \u0437\u0430\u043f\u0438\u0445\u0438\u0432\u0430\u043d\u0438\u044f \u0432 \u0440\u0435\u043a\u043e\u0440\u0434 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0435\u0439\u0441\u044f \u043a \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u0443\u0442\u0438, \u043d\u043e \u043c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u043a\u0438\u0434\u0430\u043b\u0438 \u0446\u0435\u043b\u0443\u044e \u043f\u0430\u043d\u0430\u043c\u043a\u0443 \u043a\u0435\u0439\u0441\u043e\u0432 (\u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043c\u043e\u0438\u0445 \u0436\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u043a\u0430\u043f\u0443\u0441\u0442\u043d\u0438\u043a\u0430\u0445), \u0433\u0434\u0435 \u044d\u0442\u043e\u0442 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0439 \u043e\u0449\u0443\u0442\u0438\u043c\u043e \u0432\u0440\u0435\u0434\u0438\u043b \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u0443, \u0438 \u0438\u0433\u0440\u043e\u043a\u0443.<\/em> <em>\u0422\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0438\u0445\u0438\u0432\u0430\u0442\u044c \u0442\u0443\u0434\u0430 \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0435\u0442\u0435, \u0437\u0430\u0447\u0435\u043c.<\/em><\/p>\n<h3>\u041c\u043d\u043e\u0433\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438<\/h3>\n<p><code>PersistentVector<\/code> \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0424\u041f-\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432, \u043d\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043f\u0440\u0438\u0448\u0451\u043b\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043a \u043c\u0435\u0441\u0442\u0443, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0431\u044b\u043b\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u0441 \u043e\u0431\u0449\u0438\u043c \u0433\u0435\u043d\u0435\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0440\u043e\u0448\u043b\u044b\u043c. \u0427\u0438\u0441\u0442\u043e \u0438\u0437 <strong>\u0441\u043f\u043e\u0440\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0430<\/strong> \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0437\u044b\u0433\u0440\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0443 \u0440\u043e\u0434\u0441\u0442\u0432\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e, \u0435\u0441\u043b\u0438 \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0451\u043c \u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0434\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u043f\u043e\u0434\u043b\u0435\u0436\u0430\u0442 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0443.<\/p>\n<p>\u0425\u0443\u0436\u0435 \u0432\u0441\u0435\u0433\u043e \u0434\u0435\u043b\u0430 \u043e\u0431\u0441\u0442\u043e\u044f\u0442 \u0443 <code>frontier<\/code>. \u042d\u0442\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0438, \u043e\u0434\u043d\u0430 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u2014 \u044d\u0442\u043e \u0442\u043e\u0447\u043a\u0430 \u043d\u0430 \u043f\u043e\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u044b\u043b\u0430 \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u0430 \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 <code>start<\/code> \u0432 \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 <code>mapSize<\/code> \u0438 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 <code>obstacles<\/code>. \u0410 \u0432\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u2014 \u044d\u0442\u043e \u0441\u0443\u043c\u043c\u0430 \u0438\u0437 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u044d\u0432\u0440\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0446\u0435\u043d\u043a\u0438 \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u0438 \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 <code>goal<\/code>. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e <code>frontier<\/code> \u0436\u0451\u0441\u0442\u043a\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c \u0441\u0440\u0430\u0437\u0443 \u043e\u0442 \u0432\u0441\u0435\u0445 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0438 \u043f\u0440\u0438 \u0441\u043c\u0435\u043d\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u0438\u0437 \u043d\u0438\u0445 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c.<\/p>\n<p><code>paths<\/code> \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0431\u043e\u043b\u0435\u0435 \u00ab\u043e\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u00bb, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0440\u043e\u0439\u0434\u0435\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0438 \u0438\u0445 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c. \u041c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u044d\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 <code>goal<\/code> \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0430\u0441\u0448\u0430\u0440\u0435\u043d\u0430 \u043c\u0435\u0436\u0434\u0443 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0446\u0435\u043b\u044f\u043c\u0438, \u043d\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435 \u043b\u043e\u0436\u043d\u043e. \u042d\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u044f\u0441\u043d\u043e \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043f\u0440\u0438\u043c\u0435\u0440\u0430:<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/kb\/re\/1d\/kbre1dyzxilttnh2njpiav_fgkw.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/kb\/re\/1d\/kbre1dyzxilttnh2njpiav_fgkw.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/kb\/re\/1d\/kbre1dyzxilttnh2njpiav_fgkw.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0422\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0434\u0432\u0430 <strong>\u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0445<\/strong> \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u0443\u0442\u0438 (\u043a <code>OrangeRed<\/code>-\u043a\u043b\u0435\u0442\u043a\u0430\u043c <code>4<\/code> \u0438 <code>5<\/code>). \u041e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u0430\u043c\u044b\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433. \u041e\u043d \u0432 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043a\u0435\u0439\u0441\u0430\u0445 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u0438 <code>2<\/code>, <code>3<\/code> \u0438 <code>4<\/code> \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b.<\/p>\n<p>\u0412 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439. \u041e\u0434\u043d\u0430\u043a\u043e \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u0430 \u0434\u043b\u044f \u0438\u0433\u0440\u043e\u043a\u0430, \u0435\u0441\u043b\u0438 \u043c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u043f\u043e\u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>paths<\/code> \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e, \u0442\u0430\u043a \u043a\u0430\u043a \u0448\u0430\u0433 <code>1<\/code> \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u043f\u0443\u0442\u0435\u0439 \u0441\u043e <code>2<\/code> \u043f\u043e <code>5<\/code> \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0451\u043d \u0437\u0430 \u0442\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0433\u0440\u043e\u043a \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442 \u043f\u0435\u0440\u0432\u044b\u043c. \u0422\u0430\u043a\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043d\u0430 \u0434\u043b\u0438\u043d\u043d\u044b\u0445 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044f\u0445 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0441 \u043a\u0443\u043c\u0443\u043b\u044f\u0442\u0438\u0432\u043d\u044b\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043a\u0443\u0440\u0430\u0436\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u043f\u0443\u0442\u044c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u0440\u0430\u043d\u0434\u043e\u043c\u0430.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0441\u0442\u0435\u0439 \u0432 \u044d\u0442\u043e\u043c \u0434\u0435\u043b\u0435 \u043d\u0435\u0442, \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043e\u0447\u0435\u043d\u044c \u0434\u0435\u0442\u0435\u0440\u043c\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0432\u0441\u0435\u0433\u0434\u0430 \u00ab\u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u00bb \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0431\u043b\u0438\u0437\u043a\u0438\u0439 \u043a \u0446\u0435\u043b\u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0445\u043e\u0434\u0430. \u041f\u0440\u0438\u0447\u0451\u043c \u0431\u043b\u0438\u0437\u043e\u0441\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0432 \u043c\u0430\u043d\u0445\u044d\u0442\u0442\u0435\u043d\u0441\u043a\u043e\u043c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 (\u0441\u043b\u0435\u0432\u0430) \u043e\u0431\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0440\u0430\u0432\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u044b (<code>heuristic<\/code> \u043e\u0431\u0430 \u0440\u0430\u0437\u0430 \u0434\u0430\u0451\u0442 <code>4<\/code>), \u0430 \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 (\u0441\u043f\u0440\u0430\u0432\u0430) \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u00ab\u0441\u0435\u0432\u0435\u0440\u043e-\u0437\u0430\u043f\u0430\u0434\u00bb \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0433\u043e\u0434\u043d\u0435\u0435, \u0447\u0435\u043c \u043d\u0430 \u00ab\u0441\u0435\u0432\u0435\u0440\u043e-\u0432\u043e\u0441\u0442\u043e\u043a\u00bb (<code>heuristic<\/code> \u0434\u0430\u0451\u0442 <code>3<\/code> \u043f\u0440\u043e\u0442\u0438\u0432 <code>5<\/code>). \u041a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c <code>priority<\/code>, \u0442\u043e \u0432\u044b\u0431\u0440\u0430\u043d \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u0442, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u043f\u043e\u043f\u0430\u043b \u0432\u043e <code>frontier<\/code> (\u0432\u0441\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u0432\u043e\u0437\u043d\u044e \u0441 <code>LIFO<\/code> \u0432 6 \u0433\u043b\u0430\u0432\u0435). \u0418\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f <code>neighbors<\/code>:<\/p>\n<pre><code class=\"fsharp\">let neighbors mapSize isObstacle pos =     [         Vector2I.Left         Vector2I.Right         Vector2I.Up         Vector2I.Down     ]     |&gt; Seq.map ^ fun p -&gt; p + pos     |&gt; Seq.filter ^ canStand mapSize isObstacle <\/code><\/pre>\n<p>\u0424\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0432\u0441\u0435 \u0441\u043e\u0441\u0435\u0434\u0438 \u0440\u0430\u0432\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u044b, \u0438 \u0438\u0445 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u043d\u0435 \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d, \u0442\u0430\u043a \u0447\u0442\u043e \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u0430\u0448\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u0430\u043a\u0438\u0435-\u0442\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u043d\u0442\u0440\u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043d\u0430 90 \u0438\u043b\u0438 180 \u0433\u0440\u0430\u0434\u0443\u0441\u043e\u0432, \u043d\u043e \u0441\u0443\u0442\u044c \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u041c\u044b \u0432\u0441\u0451 \u0442\u0430\u043a \u0436\u0435 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u043d\u0435\u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b <code>paths<\/code> \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430. \u041d\u0430\u043c \u043d\u0430\u0434\u043e \u0431\u0443\u0434\u0435\u0442 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0438\u0437 \u043d\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043e\u0446\u0435\u043d\u0438\u0432\u0430\u0442\u044c \u0438\u0445 \u0441 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e <code>goal<\/code> \u0438 \u0432 \u0442\u0435\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u0442\u044c \u043d\u0430\u0448\u0438\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e\u0441\u0442\u044f\u043c, \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0438\u0445 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u042d\u0442\u043e, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 <code>goal<\/code> \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0442\u0435\u0440\u044f\u043d\u044b \u0431\u0435\u0437\u0432\u043e\u0437\u0432\u0440\u0430\u0442\u043d\u043e, \u0442\u0430\u043a \u0447\u0442\u043e \u0438\u0445 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 (<code>ready<\/code>) \u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445.<\/p>\n<h4>\u041c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c <code>ready<\/code> \u043f\u0440\u043e\u0449\u0435 \u0432\u0441\u0435\u0433\u043e:<\/p>\n<pre><code class=\"fsharp\">let memoTryFindPath mapSize isObstacle start =     let ready = Dictionary()          fun goal -&gt;         ready.TryFind goal         |&gt; Option.defaultWith ^ fun () -&gt;             let result = tryFindPath mapSize isObstacle start goal             match result with             | Result.Error OutOfBounds -&gt;                 \/\/ \u041f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043f\u043e\u043b\u044f \u0431\u0435\u0437\u0433\u0440\u0430\u043d\u0438\u0447\u043d\u043e.                 ()             | _ -&gt; ready.[goal] &lt;- result             result <\/code><\/pre>\n<p><code>memoTryFindPath<\/code> \u2014 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0442 <code>goal<\/code>. \u0423 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0451\u043d\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0451 \u043d\u0430\u0434\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0433\u0434\u0435-\u0442\u043e \u0432 \u043d\u0435\u0434\u0440\u0430\u0445 \u0441\u0446\u0435\u043d\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u0438\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 <code>memoTryFindPath<\/code> \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c:<\/p>\n<pre><code class=\"fsharp\">let mutable tryFindPath =     PathFinder.memoTryFindPath mapSize units.Blocks starship.Position  ...  pathSrc &lt;- tryFindPath goal <\/code><\/pre>\n<p>\u0422\u0430\u043a\u043e\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0438 \u043e\u043d \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0448\u0438\u0440\u043e\u043a\u043e, \u0447\u0442\u043e \u044f \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u044e \u0432 \u0447\u0443\u0436\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0445\u0435\u043b\u043f\u0435\u0440\u044b \u0441 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u043e\u0439 <code>(f : 'a -&gt; 'b) -&gt; ('a -&gt; 'b)<\/code>. \u0412 \u0446\u0435\u043b\u043e\u043c \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0435\u0439 \u044f \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c, \u043e\u043d\u0430 \u0431\u0435\u0437\u0443\u0441\u043b\u043e\u0432\u043d\u043e \u0442\u043e\u0440\u0442, \u043d\u043e \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0435\u0451 \u043e\u0431\u043e\u0431\u0449\u0438\u0442\u044c \u0438 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0432 <code>Utils<\/code> \u043d\u0435 \u043f\u043e\u043d\u0438\u043c\u0430\u044e. \u042d\u0442\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f, \u0438 \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0434\u0438\u043a\u0430\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u0434 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u043b\u0435\u043a\u0430\u0435\u043c\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438.<\/p>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043b\u0451\u0433\u043a\u043e\u0439 \u0438 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e\u0439 <strong>\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u0438<\/strong> \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u043e\u0442\u0441\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 <code>OutOfBounds<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0446\u0435\u043b\u0435\u0432\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043f\u043e\u043b\u044f. \u0415\u0441\u043b\u0438 \u00ab\u0438\u0433\u0440\u043e\u0432\u0430\u044f \u0434\u043e\u0441\u043a\u0430\u00bb \u043d\u0435\u0432\u0435\u043b\u0438\u043a\u0430, \u0442\u043e \u0442\u0430\u043a\u0438\u0445 \u0442\u043e\u0447\u0435\u043a \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0430\u0440\u0443 \u043f\u043e\u0440\u044f\u0434\u043a\u043e\u0432 \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0442\u043e\u0447\u0435\u043a \u0432 \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u043f\u043e\u043b\u044f. \u0411\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f <code>ready<\/code> \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0431\u0438\u0442\u0430 \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0447\u043d\u0435\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u0447\u0435\u043c \u043d\u0430\u0439\u0442\u0438 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u0435. \u0412 \u0438\u0434\u0435\u0430\u043b\u0435 <code>ready<\/code> \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043d\u0430\u0434\u043e \u0442\u0440\u043e\u0433\u0430\u0442\u044c, \u043f\u043e\u043a\u0430 \u0446\u0435\u043b\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u0430 \u0447\u0435\u0440\u0435\u0437 <code>inMap<\/code>, \u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c:<\/p>\n<pre><code class=\"fsharp\">if not ^ inMap mapSize goal then Result.Error OutOfBounds elif isObstacle goal then Result.Error Obstacle else match ready.TryFind goal with | Some result -&gt; result | None -&gt;     ...      let result = tryFind ()     ready.[goal] &lt;- result     result <\/code><\/pre>\n<h4>\u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f paths<\/h4>\n<p>\u0412 <code>paths<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u043f\u0443\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u043d\u043e\u0432\u044b\u0445 <code>goal<\/code>. \u041d\u0435 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u044d\u0442\u0438 \u043f\u0443\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u0437\u044f\u0442\u044b \u043d\u0430 \u0432\u043e\u043e\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043d\u043e \u0442\u043e\u0447\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043f\u0443\u0442\u044c \u0441 <code>Cost = n<\/code>, \u0442\u043e \u043d\u0430\u043c \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043f\u0443\u0442\u0438 \u0441\u043e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c\u044e <code>&gt; n<\/code>. \u0412 \u044d\u0442\u043e\u043c \u043f\u043b\u0430\u043d\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 <code>paths<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0430 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430:<\/p>\n<pre><code class=\"fsharp\">match paths.TryFind next with | Some (PersistentVector.Conj (_, old)) when newCost &gt; old.Cost -&gt; () <\/code><\/pre>\n<p>\u041f\u0443\u0442\u0438 \u0441 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0435. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0443\u044f\u0441\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0432 <code>paths<\/code> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043f\u0430\u0434\u0430\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043a\u043b\u0435\u0442\u043a\u0438 \u0431\u044b\u043b\u0438 \u043f\u043e\u043c\u0435\u0449\u0435\u043d\u044b \u0432\u043e <code>frontier<\/code>. \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e, \u0435\u0441\u043b\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0443\u0436\u0435 \u0432\u043e \u0444\u0440\u043e\u043d\u0442\u0438\u0440\u0435, \u0430 <code>newCost = old.Cost<\/code>, \u0442\u043e \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0435\u0433\u043e \u0442\u0443\u0434\u0430 \u0435\u0449\u0451 \u0440\u0430\u0437. \u0422\u0430\u043a\u0436\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043f\u0440\u0438 \u043c\u043d\u043e\u0433\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u043c \u043f\u043e\u0438\u0441\u043a\u0435, \u0441\u0432\u044f\u0437\u043a\u0430 \u00ab\u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 <code>paths<\/code> =&gt; \u0431\u044b\u043b\/\u0435\u0441\u0442\u044c \u0432\u043e <code>frontier<\/code>\u00bb \u0440\u0430\u0437\u0440\u0443\u0448\u0430\u0435\u0442\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0444\u0440\u043e\u043d\u0442\u0438\u0440 \u0443 \u043d\u0430\u0441 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043d\u043e\u0432\u044b\u0439. \u0418\u0437 \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u0435\u0442, \u0447\u0442\u043e \u0443\u0447\u0451\u0442 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0432\u043e <code>frontier<\/code> \u0442\u043e\u0447\u0435\u043a \u043d\u0430\u0434\u043e \u0432\u0435\u0441\u0442\u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e:<\/p>\n<pre><code class=\"fsharp\">let frontier = PriorityStack.singleton 0 start let traversed = HashSet.singleton start  let put cost next =     ignore ^ traversed.Add next     frontier.Put (cost + heuristic goal next) next <\/code><\/pre>\n<p>\u0418 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u043a\u0442 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0433\u043e \u043f\u0443\u0442\u0438:<\/p>\n<pre><code class=\"fsharp\">| Some (PersistentVector.Conj (previous, old)) when newCost = old.Cost -&gt;     if not ^ traversed.Contains next then         put newCost next <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043d\u044f\u0442\u044c, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043b\u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0451\u043d\u043d\u044b\u0439 \u0438\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u043f\u0443\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 <code>currentPath<\/code>, \u0442\u043e \u0435\u0441\u0442\u044c <code>currentPath = previous<\/code>. \u0415\u0441\u043b\u0438 \u0434\u0430, \u0442\u043e \u0441\u0442\u0430\u0440\u044b\u0439 \u043f\u0443\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e \u0435\u0433\u043e \u043d\u0430\u0434\u043e \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u0432\u043b\u0438\u044f\u043d\u0438\u0435 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432:<\/p>\n<pre><code class=\"fsharp\">| Some (PersistentVector.Conj (previous, old)) when newCost = old.Cost -&gt;     if not ^ traversed.Contains next then         put newCost next         if previous &lt;&gt; currentPath then             paths.[next] &lt;- currentPath.Conj ^ createStep next newCost <\/code><\/pre>\n<h4>\u0422\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0438 &lt;&gt;<\/h4>\n<p>\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u0445 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0443 \u0432\u0441\u0435\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0437\u0430 <code>O(n)<\/code>, \u0447\u0442\u043e \u0434\u043e\u0440\u043e\u0436\u0435, \u0447\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0447\u0435\u0440\u0435\u0437 <code>Conj<\/code> (\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0437\u0430\u044f\u0432\u043b\u044f\u0435\u0442 <code>O(1)<\/code>, \u043d\u043e \u044f \u043f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435 \u0438\u0441\u0445\u043e\u0434\u0438\u043b <code>O(log32n)<\/code>). \u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c, \u0442\u043e \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u043d\u0435 \u043f\u043e\u043b\u043d\u0430\u044f \u043d\u0435\u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c, \u0430 \u0444\u0430\u043a\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e <code>path.[next]<\/code> \u043d\u0435 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 <code>path.[current]<\/code>:<\/p>\n<pre><code class=\"fsharp\">path.[next] &lt;- path.[current].Conj old <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u0434\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e, \u0434\u0430\u0436\u0435 \u0432 \u0443\u0449\u0435\u0440\u0431 \u00ab\u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0439\u00bb \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438. \u0411\u044b\u0441\u0442\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u043c\u043e\u0433 \u0431\u044b \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442:<\/p>\n<pre><code class=\"fsharp\">System.Object.ReferenceEquals(     path.[next].Initial \/\/ \u0412\u0435\u043a\u0442\u043e\u0440 \u0431\u0435\u0437 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.     , path.[current] ) <\/code><\/pre>\n<p>\u041d\u043e <code>PersistentVector<\/code> \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u043a\u0430, \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 <code>list<\/code>, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c <code>Tail<\/code>-\u043e\u0432 \u2014 \u043e\u0434\u043d\u0430 \u0438\u0437 \u0441\u0443\u043f\u0435\u0440\u0441\u0438\u043b:<\/p>\n<pre><code class=\"fsharp\">property {     let! tail =         Range.constantBounded()         |&gt; Gen.int32         |&gt; Gen.list ^ Range.constant 0 10     let! head =         Range.constantBounded()         |&gt; Gen.int32     return System.Object.ReferenceEquals(         tail          , (head :: tail).Tail     ) } <\/code><\/pre>\n<p>\u041e\u0431\u044a\u0435\u043a\u0442 <code>Initial<\/code> \u0432 <code>PersistentVector<\/code> \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0447\u0442\u043e \u043f\u043e\u0441\u043b\u0443\u0436\u0438\u043b \u0431\u0430\u0437\u043e\u0439 \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 (\u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0440\u0435\u0434\u043a\u0438\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0439 <code>PersistentVector.empty<\/code>):<\/p>\n<pre><code class=\"fsharp\">property {     let! initial =         Range.constantBounded()         |&gt; Gen.int32         |&gt; Gen.list ^ Range.constant 0 10     let! last =         Range.constantBounded()         |&gt; Gen.int32     let initial = PersistentVector.ofSeq initial     return not ^ System.Object.ReferenceEquals(         initial          , initial.Conj(last).Initial     ) } <\/code><\/pre>\n<p>\u0425\u0443\u0436\u0435 \u0442\u043e\u0433\u043e, <code>Initial<\/code> \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0435, \u0442\u0430\u043a \u0447\u0442\u043e \u043e\u043d \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u0435\u043d \u00ab\u0441\u0430\u043c\u043e\u043c\u0443 \u0441\u0435\u0431\u0435\u00bb:<\/p>\n<pre><code class=\"fsharp\">property {     let! initial =         Range.constantBounded()         |&gt; Gen.int32         |&gt; Gen.list ^ Range.constant 1 10     let! last =         Range.constantBounded()         |&gt; Gen.int32     let vector =         PersistentVector.ofSeq(initial).Conj last     return not ^ System.Object.ReferenceEquals(         vector.Initial         , vector.Initial     ) } <\/code><\/pre>\n<p>\u0417\u0430\u043c\u0435\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043e\u0447\u043d\u043e\u0439 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438 \u043c\u043e\u0433 \u0431\u044b \u0432\u044b\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u043a\u043b\u044e\u0447, \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u043b\u044f <strong>\u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0433\u0430<\/strong>. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0434\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0437\u0430\u0434\u0430\u0447 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e <code>Guid<\/code>, \u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0432\u0437\u044f\u043b <code>int<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043a\u043b\u044e\u0447\u0435\u0439 \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u043d\u0435\u0441\u0451\u0442 \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u043e\u043b\u044c\u0437\u044b. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u044d\u0442\u043e\u043c\u0443 <code>Id : int<\/code> \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u0432\u0438\u0434\u0435\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0435 \u043f\u0443\u0442\u0438 (\u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f, \u043d\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043c\u044b\u0441\u043b\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u043e\u043d\u044f\u0442\u043d\u043e):<\/p>\n<pre><code class=\"fsharp\">let createStep =     let mutable nextId = 0     fun position cost -&gt; {|         Position = position         Cost = cost         Id =             let result = nextId             nextId &lt;- nextId + 1             result     |} <\/code><\/pre>\n<p>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043e\u0442\u0446\u043e\u0432\u0441\u0442\u0432\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043a <code>previous.Last.Id &lt;&gt; currentPath.Last.Id<\/code>. \u042d\u0442\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043c \u043f\u043e\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435, \u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0439\u0442\u0438 \u0435\u0449\u0451 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438 \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 <code>previous<\/code> (<code>O(log32n)<\/code>), \u0435\u0441\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c <code>previous.Id<\/code> \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043d\u043e\u0432\u043e\u043c \u0448\u0430\u0433\u0435:<\/p>\n<pre><code class=\"fsharp\">let addStep =     let mutable nextId = 0     fun position cost path -&gt;          path         |&gt; PersistentVector.conj {|             Position = position             Cost = cost             Id =                 let result = nextId                 nextId &lt;- nextId + 1                 result             PreviousId =                 \/\/ \u0417\u0430\u0434\u0443\u043c\u0430\u0439\u0442\u0435\u0441\u044c \u043d\u0430 \u0434\u043e\u0441\u0443\u0433\u0435, \u043a\u0430\u043a \u0425\u041c \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0442\u0438\u043f\u044b `path` \u0438 `p`                 path.TryLast                 |&gt; Option.map ^ fun p -&gt; p.Id         |} <\/code><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0439 \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code class=\"fsharp\">module PersistentVector =     let (|Last|_|) vector = PersistentVector.tryLast vector  let createPathFinder mapSize isObstacle start =     let createStep =         let mutable nextId = 0         fun position cost -&gt; {|             Position = position             Cost = cost             Id =                 let result = nextId                 nextId &lt;- nextId + 1                 result         |}      let paths =         PersistentVector.empty         |&gt; addStep start 0         |&gt; Dictionary.singleton start      let ready = Dictionary()          let readOnlyPaths = paths.AsReadOnly()          fun goal -&gt;         if not ^ inMap mapSize goal then Result.Error OutOfBounds         elif isObstacle goal then Result.Error Obstacle else         match ready.TryFind goal with         | Some result -&gt; result         | None -&gt;             let frontier = PriorityStack.singleton 0 start             let traversed = HashSet.singleton start              let put cost next =                 ignore ^ traversed.Add next                 frontier.Put (cost + heuristic goal next) next              let rec tryFind () =                 match frontier.TryTake () with                 | None -&gt; Result.Error Unreachable                 | Some (Eq goal) -&gt;                     let path = paths.[goal]                                    Ok {|                         Path = path                         Cost = path.Last.Cost                         Goal = goal                         Start = start                         Paths = this.Paths                         Traversed = traversed :&gt; _ IReadOnlySet                         Frontier = List.ofSeq ^ frontier.AsSeq()                     |}                 | Some current -&gt;                     let currentPath = paths.[current]                     let newCost = currentPath.Last.Cost + 1                     for next in neighbours mapSize isObstacle current do                         match paths.TryFind next with                         | Some (PersistentVector.Last old) when newCost &gt; old.Cost -&gt; ()                         | Some (PersistentVector.Last old) when newCost = old.Cost -&gt;                             if not ^ traversed.Contains next then                                 put newCost next                                 if old.PreviousId &lt;&gt; Some currentPath.Last.Id then                                     paths.[next] &lt;- addStep next newCost currentPath                         | _ -&gt;                             put newCost next                             paths.[next] &lt;- addStep next newCost currentPath                     tryFind ()             let result = tryFind ()             ready.[goal] &lt;- result             result <\/code><\/pre>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e \u043e\u043d \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u043e\u0438\u0441\u043a, \u043d\u043e \u0435\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u043d\u0451\u043c \u043b\u0435\u0436\u0438\u0442 \u043d\u043e\u0432\u044b\u0439 <code>traversed<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 <code>readOnlyPaths<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0430\u0441\u0430\u0434\u043e\u043c \u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438, \u0432\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435 \u0447\u0435\u0433\u043e \u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c\u0441\u044f \u0438 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043a\u0430\u0436\u0434\u043e\u0439 \u043d\u043e\u0432\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u043e\u0439 \u043f\u043e\u0438\u0441\u043a\u0430. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442, \u0442\u043e \u0441\u043b\u0435\u043f\u043e\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e. \u0415\u0441\u043b\u0438 \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e <code>traversed<\/code>, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u043e\u0447\u0435\u043d\u044c \u0431\u043b\u0438\u0437\u043a\u0438\u0439 \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e \u043a \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438:<\/p>\n<pre><code class=\"fsharp\">pathFound.Paths |&gt; Seq.filter ^ fun p -&gt; pathFound.Traversed.Contains p.Key |&gt; Seq.map ^ fun p -&gt; p.Key, p.Value |&gt; readOnlyDict <\/code><\/pre>\n<p>\u0421\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043d\u0430\u0440\u0443\u0436\u0438 (\u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0437\u043e\u0432\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430), \u0435\u0441\u043b\u0438 \u043d\u0435 \u0437\u0430\u0442\u044f\u0433\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0434\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430. \u041d\u043e \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043e\u043a\u0430\u0436\u0435\u043c\u0441\u044f \u0437\u0430 \u0431\u043e\u0440\u0442\u043e\u043c \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u043e\u0431 \u044d\u0442\u043e\u0439 \u0448\u0442\u0443\u043a\u0435 \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u0437\u0430\u0440\u0430\u043d\u0435\u0435. \u0415\u0441\u043b\u0438 \u0443\u0432\u0435\u0440\u0435\u043d\u044b \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u043d\u0430\u0431\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 (\u043c\u043d\u0435 \u043d\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0435\u043d\u043d\u043e), \u0442\u043e \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0439\u0442\u0435. \u0415\u0441\u043b\u0438 \u043d\u0435 \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0442\u043e \u043d\u0430\u0439\u0434\u0438\u0442\u0435 \u0441\u043f\u043e\u0441\u043e\u0431 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u043c\u043e\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043b\u0438\u0431\u043e \u0447\u0435\u0440\u0435\u0437 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u043e\u0432, \u043b\u0438\u0431\u043e \u0447\u0435\u0440\u0435\u0437 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a-\u043d\u044b\u0447\u0435\u043a.<\/p>\n<h3>\u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0434\u043e\u043c \u043d\u0430\u043f\u0435\u0440\u0451\u0434<\/h3>\n<p>\u041f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u0433\u043b\u0430\u0432\u044b \u043c\u043e\u0436\u0435\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u044f \u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u043f\u043e \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u043f\u043b\u0430\u043d\u0443. \u0414\u0435\u0441\u043a\u0430\u0442\u044c, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0441\u044f \u043e \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u0430\u0445, \u043d\u0430\u0448\u0451\u043b \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043d\u0442\u0440\u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u043b \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c, \u0437\u0430\u043a\u043e\u0434\u0438\u043b \u0435\u0433\u043e \u0438 \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b \u043d\u0430 \u0441\u043e\u0442\u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432. \u042d\u0442\u043e \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435 \u043b\u043e\u0436\u043d\u043e, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0431\u044b\u043b\u0430 \u0438\u043d\u043e\u0439.<\/p>\n<p>\u041c\u043d\u0435 \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0441 \u043d\u0430\u0438\u0432\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u0430\u043a, \u043d\u043e \u043d\u0435 \u0431\u044b\u043b\u043e \u044f\u0441\u043d\u043e, \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0435\u0451 \u0437\u0430\u043a\u043e\u0434\u0438\u043b, \u043f\u043e\u0433\u043e\u043d\u044f\u043b \u0432 \u00ab\u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438\u00bb, \u043f\u043e\u043d\u044f\u043b, \u043a\u0430\u043a\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f\u043c \u0438 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043b \u043a \u0442\u0435\u0441\u0442\u0430\u043c. \u0422\u0435\u0441\u0442\u044b \u0434\u0430\u043b\u0438 \u043c\u043d\u0435 \u043a\u043e\u043d\u0442\u0440\u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438 \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u044b, \u0430 \u043e\u043d\u0438 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u0440\u0438\u0432\u0435\u043b\u0438 \u043a \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u043d\u043e\u0432\u043e\u0433\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430. \u041b\u0438\u0448\u044c \u043f\u0440\u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f <code>PersistentVector<\/code> \u0432\u043e \u043c\u043d\u0435 \u0432\u0437\u044b\u0433\u0440\u0430\u043b \u0432\u0438\u0437\u0438\u043e\u043d\u0435\u0440, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u043e \u043e\u0449\u0443\u0442\u0438\u043c\u043e\u0439 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043d\u0430 \u0436\u0435\u043b\u0435\u0437\u043e \u044f \u043d\u0435 \u0434\u043e\u0448\u0451\u043b.<\/p>\n<p>\u0424\u0440\u0430\u0437\u0443 <code>\"\u0422\u0435\u0441\u0442\u044b \u0434\u0430\u043b\u0438 \u043c\u043d\u0435 \u043a\u043e\u043d\u0442\u0440\u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0438 \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u044b\"<\/code> \u043d\u0430\u0434\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e. \u0420\u0435\u0447\u044c \u043d\u0435 \u043e \u043d\u0435\u043a\u043e\u0435\u0439 \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u043c \u043e\u0431\u0435\u0449\u0430\u0435\u0442 TDD \u0438 \u0435\u0439 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0438\u0434\u0435\u043e\u043b\u043e\u0433\u0438\u0438. \u042f \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b \u0432 \u0440\u0443\u043a\u0438 \u043a\u043e\u043d\u0442\u0440\u043f\u0440\u0438\u043c\u0435\u0440\u044b, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0447\u0435\u0440\u0435\u0434\u043e\u0439 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0443\u043c\u043e\u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043f\u0440\u0438\u0448\u0451\u043b \u043a \u043a\u043e\u0440\u043d\u0435\u0440-\u043a\u0435\u0439\u0441\u0430\u043c, \u0430 \u043e\u0442 \u043d\u0438\u0445 \u2014 \u043a \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430. \u042d\u0442\u043e\u0442 \u00ab\u0434\u0430\u0440\u00bb \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u043b \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0442\u043e\u0438\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435.<\/p>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0432 \u044d\u0442\u043e\u0439 \u0438 \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u044f \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u0441 \u0431\u0438\u043b\u0434\u0435\u0440\u043e\u043c <code>property<\/code>. \u0421\u0440\u0435\u0434\u0438 \u043c\u043e\u0438\u0445 <s>\u0430\u043b\u044c\u0444\u0430\u0447\u0435\u0439<\/s> \u0430\u043b\u044c\u0444\u0430-\u0442\u0435\u0441\u0442\u0435\u0440\u043e\u0432 \u0431\u044b\u043b\u0438 \u043b\u044e\u0434\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0447\u0438\u0442\u0430\u043b\u0438, \u0447\u0442\u043e \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u0441\u0442\u043e\u0438\u0442, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442. \u0412\u0441\u0451-\u0442\u0430\u043a\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0431\u044b\u043b\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438, \u0447\u0442\u043e\u0431\u044b \u0438\u0445 \u0441\u043c\u044b\u0441\u043b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u044c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437 \u043a\u043e\u0434\u0430. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435 \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u044b \u0432 \u0442\u0435\u043a\u0441\u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0430\u043b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u043d\u043e\u0447\u0442\u0435\u043d\u0438\u044f.<\/p>\n<p><code>property<\/code> \u2014 \u044d\u0442\u043e \u0431\u0438\u043b\u0434\u0435\u0440 \u0438\u0437 \u043f\u0430\u043a\u0435\u0442\u0430 <code>Hedgehog<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0440\u0430\u043d\u0434\u043e\u043c\u043d\u044b\u043c \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u00ab\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u00bb, \u0447\u0442\u043e \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u044f\u044e\u0442 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442\u0443. \u041c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0442\u0430\u043a \u0432 \u0441\u0436\u0430\u0442\u043e\u043c \u0432\u0438\u0434\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u0434\u0435\u043e\u043b\u043e\u0433\u0438\u0438 <code>Property Based Testing<\/code>. \u0422\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0430\u0441\u043f\u0435\u043a\u0442 \u0432 \u044d\u0442\u043e\u043c \u0446\u0438\u043a\u043b\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u044f \u0441\u0440\u0430\u0437\u0443 \u043f\u0435\u0440\u0435\u0439\u0434\u0443 \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0445\u043e\u0434\u0430\u043c \u0438 \u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u044f\u043c. \u041d\u043e \u0435\u0441\u043b\u0438 \u043a\u043e\u043c\u0443 \u043d\u0430\u0434\u043e, \u0442\u043e AI \u042f\u043d\u0434\u0435\u043a\u0441\u0430 \u0434\u0430\u0451\u0442 \u0432\u043f\u043e\u043b\u043d\u0435 \u0432\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 PBT, \u0430 \u0437\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a <a href=\"https:\/\/fsharpforfunandprofit.com\/posts\/property-based-testing\/\" rel=\"noopener noreferrer nofollow\">\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c\u0443 \u0446\u0438\u043a\u043b\u0443<\/a> \u0438 \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 <a href=\"https:\/\/hedgehogqa.github.io\/fsharp-hedgehog\/\" rel=\"noopener noreferrer nofollow\">Hedgehog<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/fscheck.github.io\/FsCheck\/\" rel=\"noopener noreferrer nofollow\">FsCheck<\/a>.<\/p>\n<p>\u041d\u0430\u0440\u044f\u0434\u0443 \u0441 <code>property<\/code> \u0432 <code>Hedgehog<\/code> \u0435\u0441\u0442\u044c \u0431\u0438\u043b\u0434\u0435\u0440 <code>gen<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u043d\u0434\u043e\u043c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0445 \u043f\u0440\u0435\u0434\u0438\u043a\u0430\u0442\u043e\u0432. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044f 4 \u043d\u0430 4, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044c \u0442\u0430\u0439\u043b\u043e\u0432 \u0437\u0430\u043d\u044f\u0442\u044b \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u044f\u043c\u0438, \u0430 \u0441\u0440\u0435\u0434\u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0432\u044b\u0431\u0440\u0430\u043d\u044b \u0442\u043e\u0447\u043a\u0430 <code>start<\/code> \u0438 5 \u0446\u0435\u043b\u0435\u0439:<\/p>\n<pre><code class=\"fsharp\">open Hedgehog  let mapSize = Vector2I.One * 4  let genInput = gen {     let! rnd =         Range.constantBounded()         |&gt; Gen.int32         |&gt; Gen.map System.Random     let obstacles, spaces =         [             for x in 0..mapSize.X-1 do                 for y in 0..mapSize.Y-1 do                     Vector2I(x, y)         ]         |&gt; List.randomShuffleWith rnd         |&gt; List.splitAt (mapSize.X * mapSize.Y \/ 4)     match spaces with     | start :: goals -&gt;         return {|             Start = start             Goals = List.take 5 goals             Obstacles = obstacles |&gt; List.sortBy ^ fun p -&gt; p.X, p.Y         |}     | unexpected -&gt;         return failwith $\"Unexpected: %A{unexpected}\" } <\/code><\/pre>\n<p>\u041a\u0440\u0430\u0439\u043d\u0435 \u0432\u0430\u0436\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u044c \u0432 \u0441\u0446\u0435\u043d\u0443 \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u043e\u0433\u043e \u0440\u0435\u043a\u043e\u0440\u0434\u0430 \u0432 \u0433\u043e\u0442\u043e\u0432\u043e\u043c \u043a \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0438\u0434\u0435 (<code>int * int<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>Vector2I<\/code> \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435). \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0440\u0430\u0437\u043c\u0435\u0440 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u043c\u0430\u043b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u043f\u0440\u0438\u043d\u0442\u0435 \u0432 \u043b\u043e\u0433\u0438 \u0440\u0435\u043a\u043e\u0440\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0432\u0435\u0434\u0435\u043d \u0446\u0435\u043b\u0438\u043a\u043e\u043c, \u0442\u0430\u043a \u0447\u0442\u043e \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u0438\u0442\u044c \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a \u0441\u0446\u0435\u043d\u044b. \u042d\u0442\u043e \u0441\u0447\u0430\u0441\u0442\u043b\u0438\u0432\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435. \u041e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0439\u0442\u0435 \u0441 \u0447\u0435\u0433\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e. \u0421\u043a\u0430\u0436\u0435\u043c, \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0439\u0442\u0435 \u0432 <code>json<\/code> \u0438 \u0432\u044b\u0432\u0435\u0434\u0438\u0442\u0435 \u0435\u0433\u043e \u0432 \u043b\u043e\u0433\u0438 \u0442\u0435\u0441\u0442\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0442\u043e\u043c \u0440\u0443\u043a\u0430\u043c\u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u043a\u043e\u0434\u0435 \u0441\u0446\u0435\u043d\u044b.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0442\u0435\u0441\u0442\u043e\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e \u043c\u043d\u043e\u0433\u043e\u0440\u0430\u0437\u043e\u0432\u0430\u044f \u0438 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0443\u0442\u044c \u043a \u0446\u0435\u043b\u0438:<\/p>\n<pre><code class=\"fsharp\">property {     let! data = genInput      let obstacles = HashSet data.Obstacles     let tryFind = createPathFinder mapSize obstacles.Contains data.Start      let result =         data.Goals         |&gt; List.map ^ fun goal -&gt;             goal             , tryFind goal             |&gt; Result.map ^ fun p -&gt;                  p.Path                 |&gt; Seq.map ^ fun p -&gt; p.Cost, p.Position                 |&gt; List.ofSeq             , tryFindPath mapSize obstacles.Contains data.Start goal             |&gt; Result.map ^ fun p -&gt;                  p.Path                 |&gt; Seq.map ^ fun p -&gt; p.Cost, p.Position                 |&gt; List.ofSeq                  counterexample(         String.concat \"  \\n\" ^ seq {             for index, (goal, actual, expected) in Seq.indexed result do                 $\"#%i{index}:\"                 $\"Goal: %A{goal}\"                 $\"%A{actual}\"                 $\"%A{expected}\"         }     )      return         result         |&gt; List.forall ^ fun (_, actual, expected) -&gt; actual = expected }  \/\/ \u0413\u0434\u0435-\u0442\u043e \u0432 `Ready` \u0441\u0435\u043a\u0446\u0438\u0438 \u0441\u0446\u0435\u043d\u044b\/\u043d\u043e\u0434\u044b. |&gt; Property.render |&gt; GD.print <\/code><\/pre>\n<p>\u042d\u0442\u043e, \u0432 \u043e\u0431\u0449\u0435\u043c-\u0442\u043e, \u0433\u043b\u0430\u0432\u043d\u044b\u0439 \u0442\u0435\u0441\u0442 \u0432\u0435\u0447\u0435\u0440\u0430. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0433\u043e \u044f \u043d\u0430\u0431\u0440\u0451\u043b \u043d\u0430 \u043a\u0435\u0439\u0441 \u0441 <code>4 vs 5<\/code> \u0438\u0437 \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0442\u0430\u0442\u044c\u0438 \u0438 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u0435\u0439\u0441\u043e\u0432 \u043f\u043e\u043c\u0435\u043d\u044c\u0448\u0435.<\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0430\u0441\u0441\u0435\u0440\u0442\u043e\u0432, \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0434\u043b\u044f \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043d\u0430\u0434\u043e \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u0432 <code>counterexample<\/code> (\u0442\u0443\u0434\u0430 \u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u0442\u0438\u0442\u044c \u0432\u044b\u0448\u0435\u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0439 <code>json<\/code>). \u041e\u0442\u0442\u0443\u0434\u0430 \u043e\u043d\u0430 \u043f\u043e\u0439\u0434\u0451\u0442 \u0434\u0430\u043b\u044c\u0448\u0435, \u0435\u0441\u043b\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u043f\u043e\u0441\u044b\u043b\u043a\u0430 \u0437\u0430\u0432\u0430\u043b\u0438\u0442\u0441\u044f. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0430 <code>result<\/code>. \u0415\u0441\u043b\u0438 \u0431\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u044b\u043b\u043e \u043c\u0435\u043d\u044c\u0448\u0435, \u0442\u043e \u043c\u044b \u0431\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438 <code>List.forall<\/code> \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0434 <code>data.Goals<\/code>.<\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0442\u0435\u0441\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442, \u0447\u0442\u043e \u043f\u043e\u0438\u0441\u043a \u043d\u0430 \u043e\u0434\u043d\u0443 \u0438 \u0442\u0443 \u0436\u0435 \u0446\u0435\u043b\u044c \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0443\u0442\u044c \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u0438\u0435 \u0446\u0435\u043b\u0438 \u0431\u044b\u043b\u0438 \u0434\u043e \u044d\u0442\u043e\u0433\u043e:<\/p>\n<pre><code class=\"fsharp\">property {     let! data = gen {         let! data = genInput          let! goals =             Gen.item data.Goals             |&gt; Gen.list ^ Range.singleton (2 * data.Goals.Length)          return {| data with Goals = goals |}     }      let obstacles = HashSet data.Obstacles     let tryFind = memoTryFindPath mapSize obstacles.Contains data.Start      let result =         data.Goals         |&gt; List.map ^ fun goal -&gt;             goal             , tryFind goal             |&gt; Result.map ^ fun p -&gt;                  p.Path                 |&gt; Seq.map ^ fun p -&gt; p.Cost, p.Position                 |&gt; List.ofSeq         |&gt; List.groupBy fst         |&gt; List.map ^ fun (goal, items) -&gt;             goal, List.map snd items                  counterexample(         String.concat \"  \\n\" ^ seq {             for index, (goal, path) in Seq.indexed result do                 $\"#%i{index}:\"                 $\"Goal: %A{goal}\"                 $\"%A{path}\"         }     )      return         result         |&gt; List.forall ^ fun (_, results) -&gt;             let actual =                 results                 |&gt; List.distinct                 |&gt; List.length             actual = 1 } <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c <code>ready<\/code> \u0441\u043b\u043e\u0432\u0430\u0440\u0451\u043c (\u0441 \u043f\u0443\u0442\u044f\u043c\u0438), \u0430 \u043d\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u0432 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u043c\u043e\u0438\u0445 \u043f\u0435\u0440\u0432\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439.<\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0434\u0451\u043d\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0431\u043b\u0438\u0437\u043a\u0438\u043c\u0438 \u043a \u0438\u0434\u0435\u0430\u043b\u0443. \u0418\u0445 \u0448\u0440\u0438\u043d\u043a\u0435\u0440\u044b (\u0447\u0442\u043e \u044d\u0442\u043e, \u0438\u0437\u0443\u0447\u0430\u0439\u0442\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e) \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442. \u0420\u0430\u0437\u043c\u0435\u0440\u044b \u043f\u043e\u043b\u044f, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0438\u0439 \u0438 \u0446\u0435\u043b\u0435\u0439 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u044b. \u0412\u0441\u0451 \u044d\u0442\u043e \u043b\u0435\u0433\u043a\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0435\u0441\u043b\u0438 \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0430\u0437\u0430\u043c\u0438 PBT. \u041d\u043e \u044f \u043e\u0441\u0442\u0430\u0432\u0438\u043b \u0432\u0441\u0451 \u043a\u0430\u043a \u0435\u0441\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a <s>\u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u043b\u0435\u0437\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u044e<\/s> \u0434\u0430\u0436\u0435 \u0442\u0430\u043a\u043e\u0439 \u0434\u0443\u0431\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0442\u0435\u0441\u0442\u043e\u0432 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043b\u0443\u0447\u0448\u0435 \u0438 \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u043e\u0432.<\/p>\n<p>\u0415\u0449\u0451 \u043e\u0434\u043d\u0438\u043c \u0432\u0430\u0436\u043d\u044b\u043c \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u044b\u043b\u043e \u0442\u043e, \u0447\u0442\u043e \u044f \u0432\u044b\u0432\u043e\u0434\u0438\u043b \u0443\u0439\u043c\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435. \u041c\u043d\u0435 \u0431\u044b\u043b \u0432\u0438\u0434\u0435\u043d \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0443\u0442\u044c, \u043d\u043e \u0438 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0432\u0438\u0434\u0435 \u043a\u043b\u0435\u0442\u043e\u043a <code>traversed<\/code>, <code>frontier<\/code> \u0438 <code>paths<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u0442\u0440\u043e\u0438\u0442 \u043f\u0443\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 \u0431\u0443\u043a\u0432\u044b <code>\u0413<\/code> \u0438 \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435\u0445 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u0432\u043e <code>frontier<\/code>. \u041a\u043e\u0433\u0434\u0430 \u043e\u043d \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0437\u0430\u0433\u043b\u044f\u0434\u044b\u0432\u0430\u0442\u044c \u0432 \u0442\u043e\u0447\u043a\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438, \u044d\u0442\u043e \u043f\u043e\u0432\u043e\u0434 \u0434\u043b\u044f \u0431\u0435\u0441\u043f\u043e\u043a\u043e\u0439\u0441\u0442\u0432\u0430. \u0421\u043a\u0430\u0436\u0435\u043c, \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442\u043d\u044b\u0445 <code>Cost<\/code> \u0432 \u0442\u0435\u0445 \u0436\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u0437\u0430\u043a\u0440\u0430\u0441\u043a\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u043e\u043c (\u043a\u0430\u043a \u0432 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441 <code>PriorityQueue<\/code> \u0432 6 \u0433\u043b\u0430\u0432\u0435).<\/p>\n<p>\u041f\u0443\u0442\u044c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u0436\u0435, \u043d\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0437\u0430\u0433\u043b\u044f\u043d\u0435\u0442 \u0432 <code>x * y<\/code> \u0442\u043e\u0447\u0435\u043a, \u0447\u0442\u043e \u0432 \u0440\u0430\u0437\u044b \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u043d\u044b\u0435 <code>x + y - 1<\/code>. \u0418\u043c\u0435\u044f \u0442\u0430\u043a\u0443\u044e \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0443, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043b\u0435\u0433\u043a\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u0438\u043d <code>property<\/code>-\u0442\u0435\u0441\u0442, \u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u044d\u0442\u0438\u043c \u043d\u0430\u0434\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u0442\u044c \u043e \u0434\u0430\u043d\u043d\u043e\u043c \u0444\u0430\u043a\u0442\u0435, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0438 \u043d\u0443\u0436\u043d\u0430 \u0443\u0442\u044f\u0436\u0435\u043b\u0451\u043d\u043d\u0430\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f. \u041e\u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438, \u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0442\u043e\u0447\u043d\u043e \u043e\u0442 \u043d\u0435\u0451 \u0432\u044b\u0438\u0433\u0440\u044b\u0432\u0430\u0435\u0442. \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u0434\u043e\u0442\u0430\u0449\u0438\u0442\u044c \u0432\u0441\u0451 \u044d\u0442\u043e \u0434\u0435\u043b\u043e \u0434\u043e UI \u0438 \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0440\u0443\u0447\u043a\u0443 <code>\u0432\u043a\u043b\/\u0432\u044b\u043a\u043b<\/code>.<\/p>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435 \u043d\u0430 \u043c\u0435\u0441\u0442\u0435 \u0438\u043d\u0434\u0438-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0432 \u044f \u0431\u044b \u043f\u0440\u0438\u0437\u0430\u0434\u0443\u043c\u0430\u043b\u0441\u044f \u043d\u0430\u0434 \u0442\u0435\u043c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0442\u0435\u0440\u044f\u0435\u0442 \u0438\u0433\u0440\u043e\u043a \u0438\u0437-\u0437\u0430 \u043d\u0435\u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0438\u043b\u0438 \u0432\u043e\u0432\u0441\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a. \u042f \u0443\u0436\u0435 \u043f\u043e\u0447\u0442\u0438 \u0441\u043c\u0438\u0440\u0438\u043b\u0441\u044f \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u0433\u0440\u0443\u0431\u0435\u0439\u0448\u0430\u044f \u043d\u0435\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u043f\u0440\u0435\u043f\u043e\u0434\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a\u0430\u043a \u043d\u0435\u043a\u0430\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0430 \u00ab\u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f\u00bb. \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0443, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u044b\u0437\u0432\u0430\u043d\u0430 \u0431\u0430\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u043c \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e-\u0447\u0430\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0443\u0447\u0448\u0435 \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 \u043f\u043e\u0438\u0441\u043a \u0438 \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0431\u0430\u0433\u043e\u0432. \u041d\u043e \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u043c, \u0447\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c \u0431\u0430\u0433 \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0443 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435, \u0447\u0435\u043c \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u044f \u043d\u0435 \u0438\u043c\u0435\u044e \u043f\u0440\u0438\u0432\u044b\u0447\u043a\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u043c\u0430\u0448\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u0447\u0442\u043e \u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u0432\u043e \u043c\u043d\u0435 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u0441\u043e\u043c\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u0441\u0442\u0440\u0435\u0447\u0435 \u0441 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0432 \u0438\u0433\u0440\u0435: \u00ab\u042d\u0442\u043e \u043c\u0435\u043d\u044f \u043f\u0430\u043c\u044f\u0442\u044c \u043f\u043e\u0434\u0432\u043e\u0434\u0438\u0442, \u0438\u043b\u0438 \u0438\u0433\u0440\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u043e, \u0447\u0442\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0434\u0435\u043b\u0430\u0442\u044c?\u00bb \u0410 \u043a\u043e\u0433\u0434\u0430 \u044f \u0438\u0433\u0440\u0430\u044e \u0432 roguelike, \u0442\u043e \u0443 \u043c\u0435\u043d\u044f \u0435\u0449\u0451 \u0438 \u043f\u0440\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e \u0432 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u0442\u0430\u043a \u0447\u0442\u043e \u044f \u043f\u043e\u0447\u0442\u0438 \u043d\u0435 \u0440\u0430\u043f\u043e\u0440\u0442\u0443\u044e \u043e \u0431\u0430\u0433\u0430\u0445.<\/p>\n<h3>\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043f\u044b\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0432 functional-first \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445. \u042f \u043d\u0435 \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u043b \u043a \u043f\u043b\u044f\u0441\u043a\u0430\u043c \u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u0430\u043c\u0438, \u0441\u043f\u0430\u043d\u0430\u043c\u0438 \u0438 \u043f\u0440\u043e\u0447\u0435\u0439 \u0444\u0438\u0433\u043d\u0451\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0442\u0430\u043a \u043b\u044e\u0431\u044f\u0442 \u0431\u0430\u0439\u0442\u043e\u043b\u044e\u0431\u044b. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u0438\u0445 \u0432\u0440\u0435\u0434\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e \u0442\u0430\u043a\u0438\u0435 \u043c\u0430\u0448\u0438\u043d\u043d\u044b\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0442\u0441\u0435\u043a\u0430\u044e\u0442 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0434\u043e\u0440\u043e\u0436\u043a\u0438 \u0434\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0444\u0438\u0447. \u041e\u043d\u0438 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0431\u043e\u043a\u0443, \u0447\u0442\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0441\u043e\u0432\u043e\u043a\u0443\u043f\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u043d\u0435 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435. \u041d\u0430\u0441\u0442\u0430\u0438\u0432\u0430\u044e \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043f\u043e\u0431\u043b\u0438\u0436\u0435 \u043a \u0437\u0435\u043c\u043b\u0435 \u0438 \u0441\u043a\u043b\u043e\u043d\u044f\u0442\u044c\u0441\u044f \u043a \u0442\u0435\u043c \u0445\u043e\u0434\u0430\u043c, \u0447\u0442\u043e \u0432\u044b\u0442\u0435\u043a\u0430\u044e\u0442 \u0438\u0437 \u0441\u0430\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u0432\u043e\u0451\u043c \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430 \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438\u043c \u0441\u043e\u0437\u043d\u0430\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u0430\u043c\u043e \u043f\u043e \u0441\u0435\u0431\u0435 \u043b\u044e\u0431\u0438\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u044d\u043a\u0441\u0442\u0440\u0435\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u0435\u0439\u0441\u044b, \u0440\u0430\u043d\u0436\u0438\u0440\u0443\u0435\u0442 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0451, \u0447\u0442\u043e \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u043f\u043e\u043b\u0435 \u0437\u0440\u0435\u043d\u0438\u044f, \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/3y\/rp\/0h\/3yrp0h3wwkoekfy57lptshixeta.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/3y\/rp\/0h\/3yrp0h3wwkoekfy57lptshixeta.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/3y\/rp\/0h\/3yrp0h3wwkoekfy57lptshixeta.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0423 \u043d\u0435\u0433\u043e, \u043f\u0440\u0430\u0432\u0434\u0430, \u043d\u0438\u0444\u0438\u0433\u0430 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f. \u0423\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e \u044d\u0442\u043e \u043a\u0430\u043a \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 \u0441 \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u043d\u043e\u0439 \u0432\u044b\u0448\u043a\u043e\u0439. \u0414\u0430\u0436\u0435 \u043d\u0430\u043c\u0430\u0445\u0430\u043d\u043d\u044b\u0435 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u044b \u0432\u0435\u0434\u0443\u0442 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u043b\u044e\u0434\u0438 \u0441 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0440\u043e\u0447\u043d\u043e\u0439 \u043f\u0430\u043c\u044f\u0442\u044c\u044e. \u041c\u0430\u0448\u0438\u043d\u044b \u044d\u0442\u0438\u0445 \u0434\u0435\u0444\u0435\u043a\u0442\u043e\u0432 \u043b\u0438\u0448\u0435\u043d\u044b. \u041e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043c\u043e\u0447\u044c, \u043d\u043e \u0443 \u043d\u0438\u0445 \u0442\u0443\u0445\u043b\u043e \u0441 \u0446\u0435\u043b\u0435\u043f\u043e\u043b\u0430\u0433\u0430\u043d\u0438\u0435\u043c, \u0442\u0430\u043a \u0447\u0442\u043e \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0434\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u0434 \u0440\u0430\u0431\u043e\u0442\u0430\u043b \u0441 \u0442\u043e\u0439 \u0436\u0435 \u043c\u043e\u0434\u0435\u043b\u044c\u044e, \u0447\u0442\u043e \u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u043d\u043e-\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0441\u0432\u044f\u0437\u044c: \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0441\u0441\u0438\u0441\u0442\u0438\u0440\u0443\u044e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u043f\u0440\u0438\u0437\u0432\u0430\u043d\u044b \u043f\u0440\u0435\u0434\u0432\u043e\u0441\u0445\u0438\u0449\u0430\u0442\u044c \u0435\u0433\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0438\u0433\u0430\u0435\u0442\u0441\u044f \u0437\u0430 \u0441\u0447\u0451\u0442 \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f DDD.<\/p>\n<p>\u0421 \u0440\u043e\u0441\u0442\u043e\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u043f\u0430\u0441\u0442\u044c \u0438\u0437 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430, \u0438 \u0442\u043e\u0433\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0432\u0435\u0442\u0432\u0438\u0441\u0442\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u044f\u0445 \u0441\u043e\u0439\u0434\u0451\u0442 \u043d\u0430 \u043d\u0435\u0442. \u042d\u0442\u043e \u0430\u0431\u0441\u0443\u0440\u0434\u043d\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u0435\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u043e\u0431 \u0438\u0433\u0440\u0430\u0445, \u043d\u043e \u043e\u043d \u0432\u043f\u043e\u043b\u043d\u0435 \u0432\u0435\u0440\u043e\u044f\u0442\u0435\u043d \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0433\u043e \u041f\u041e. \u041d\u0430 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0434\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043c\u0430\u0441\u0441\u0438\u0432\u0430\u043c \u0438 \u0442. \u043f. \u0434\u0438\u043d\u043e\u0437\u0430\u0432\u0440\u0430\u043c, \u043e\u0434\u043d\u0430\u043a\u043e \u0438\u0445 \u043d\u0430\u0434\u043e \u043a\u0430\u043a-\u0442\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0412 \u044d\u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0440\u0430\u0437\u0432\u0435\u0441\u0438\u0441\u0442\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0438 \u0441 PBT \u0432\u044b\u0441\u0442\u0440\u0435\u043b\u0438\u0432\u0430\u044e\u0442 \u0435\u0449\u0451 \u0440\u0430\u0437, \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043a\u043b\u0435\u043f\u0430\u0442\u044c \u043a\u0443\u0447\u0443 <code>property<\/code>-\u0442\u0435\u0441\u0442\u043e\u0432 \u0432\u0438\u0434\u0430 \u00ab\u0431\u044b\u0441\u0442\u0440\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0432\u044b\u0434\u0430\u0451\u0442 \u0442\u043e\u0442 \u0436\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u0447\u0442\u043e \u0438 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0430\u044f\u00bb. \u041c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0432\u0438\u0434\u0435\u043b\u0438 \u0441\u0445\u043e\u0436\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441 \u043c\u043d\u043e\u0433\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u043c \u0438 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u043c \u043f\u043e\u0438\u0441\u043a\u0430\u043c\u0438 \u043f\u0443\u0442\u0438. \u0412 \u044d\u0442\u043e\u043c \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e, \u044d\u0442\u043e \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u0441\u0430\u043c\u0430\u044f \u0442\u0443\u043f\u0430\u044f \u0440\u0430\u0437\u043d\u043e\u0432\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043e\u0440\u0430\u043a\u0443\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0447\u0435\u043d\u044c \u043b\u0435\u0433\u043a\u043e \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0438 \u043d\u0435 \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u043a\u0441\u043a\u0443\u0440\u0441 \u0432 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0435 \u0424\u041f \u0437\u0430\u043a\u043e\u043d\u0447\u0435\u043d. \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0433\u043b\u0430\u0432\u0435 \u043c\u044b \u0432\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 F# \u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 Godot.<\/p>\n<hr\/>\n<p>\u041d\u041b\u041e \u043f\u0440\u0438\u043b\u0435\u0442\u0435\u043b\u043e \u0438 \u043e\u0441\u0442\u0430\u0432\u0438\u043b\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u043c\u043e\u043a\u043e\u0434 \u0434\u043b\u044f \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430\u0448\u0435\u0433\u043e \u0431\u043b\u043e\u0433\u0430:<br \/> <a href=\"https:\/\/firstvds.ru\/?utm_source=habr&amp;utm_medium=article&amp;utm_campaign=product&amp;utm_content=vds15exeptprogrev\" rel=\"noopener noreferrer nofollow\">-15% \u043d\u0430 \u0437\u0430\u043a\u0430\u0437 \u043b\u044e\u0431\u043e\u0433\u043e VDS<\/a> (\u043a\u0440\u043e\u043c\u0435 \u0442\u0430\u0440\u0438\u0444\u0430 \u041f\u0440\u043e\u0433\u0440\u0435\u0432) \u2014 <strong>HABRFIRSTVDS<\/strong>.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/926138\/\"> https:\/\/habr.com\/ru\/articles\/926138\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"\"><\/figure>\n<p>\u041c\u044b \u043a\u043e\u0432\u044b\u0440\u044f\u043b\u0438 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438 \u0447\u0435\u0440\u0435\u0437 <code>A*<\/code> \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 <a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/919448\/\" rel=\"noopener noreferrer nofollow\">\u0434\u0432\u0443\u0445 \u0433\u043b\u0430\u0432<\/a> \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0431\u044b\u043b\u0438 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0435\u043d\u044b \u043d\u0430 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0438\u0437\u044b\u0441\u043a\u0430\u0445 F#. \u0412 \u044d\u0442\u043e\u0439 \u0433\u043b\u0430\u0432\u0435 \u043c\u044b \u043e\u0442\u0434\u043e\u0445\u043d\u0451\u043c \u043e\u0442 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a \u044d\u0442\u043e\u0442 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043c\u043e\u0433 \u0431\u044b \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0431\u043e\u043b\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u043c \u0441\u0442\u0438\u043b\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>\u041e\u0433\u043b\u0430\u0432\u043b\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<h3>\u041f\u0440\u0438\u043a\u0432\u0435\u043b<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/806145\/\" rel=\"noopener noreferrer nofollow\">An incursion under C#. \u041f\u0440\u043e\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u0435\u043c F# \u0432 Godot<\/a> <\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/904306\/\" rel=\"noopener noreferrer nofollow\">\u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>\u0428\u0435\u0441\u0442\u0438\u0434\u0435\u0441\u044f\u0442\u0438\u043b\u0435\u0442\u043d\u0438\u0439 \u0437\u0430\u043a\u043b\u044e\u0447\u0451\u043d\u043d\u044b\u0439 \u0438 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u0430\u044f \u043a\u0440\u044b\u0441\u0430. F# \u043d\u0430 Godot<\/h3>\n<ul>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/846224\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1. \u0412\u0441\u0442\u0440\u0435\u0447\u0430 \u0441 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/850980\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 2. \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/856406\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 3. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b c \u043f\u0435\u0440\u0435\u0441\u0430\u0434\u043a\u0430\u043c\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/904772\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 4. \u0414\u0435\u0444\u043e\u043b\u0442\u044b, option \u0438 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/909536\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 5. \u041e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/917404\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 6. \u041a\u0430\u043a \u0434\u043e\u0431\u044b\u0442\u044c \u043d\u0435\u0447\u0442\u043e<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/919448\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 7. \u041a\u0430\u043a \u0443\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043d\u0435\u0447\u0442\u043e<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/926138\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 8. \u0417\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438<\/a> \/\/ \u043c\u044b \u0437\u0434\u0435\u0441\u044c<\/p>\n<\/li>\n<\/ul>\n<\/div>\n<\/details>\n<h3>\u041f\u0443\u0442\u044c \u0424\u041f<\/h3>\n<p>\u0412 <a href=\"https:\/\/habr.com\/ru\/companies\/first\/articles\/917404\/\" rel=\"noopener noreferrer nofollow\">6 \u0433\u043b\u0430\u0432\u0435<\/a> \u043c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0435 \u043f\u043e\u0438\u0441\u043a\u0430:<\/p>\n<pre><code class=\"fsharp\">let tryFindPath mapSize isObstacle start goal =     if not ^ inMap mapSize goal then Result.Error OutOfBounds     elif isObstacle goal then Result.Error Obstacle else     let frontier = PriorityStack.singleton 0 start     let cameFrom = Dictionary.singleton start start     let costSoFar = Dictionary.singleton start 0      let rec tryFind () =         match frontier.TryTake () with         | None -&gt; Result.Error Unreachable         | Some (Eq goal) -&gt;             let path = Stack()             path.Push goal             let rec buildPath current =                 if current &lt;&gt; start then                     let current = cameFrom.[current]                     path.Push current                     buildPath current             buildPath goal             Ok {|                 Path = List.ofSeq path                 Cost = costSoFar.[goal]                 Start = start                 Goal = goal                 CostSoFar = costSoFar.AsReadOnly()                 CameFrom = cameFrom.AsReadOnly()                 Frontier = List.ofSeq ^ frontier.AsSeq()             |}         | Some current -&gt;             let newCost = costSoFar.[current] + 1             for next in neighbours mapSize isObstacle current do                 match costSoFar.TryGetValue next with                 | true, oldCost when newCost &gt;= oldCost -&gt; ()                 | _ -&gt;                     costSoFar.[next] &lt;- newCost                     frontier.Put (newCost + heuristic goal next) next                     cameFrom.[next] &lt;- current             tryFind ()     tryFind () <\/code><\/pre>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043d\u0451\u043c \u043d\u0430\u0434\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e <code>cameFrom : Dictionary&lt;Vector2I, Vector2I&gt;<\/code>. \u041a\u0430\u0436\u0434\u044b\u0439 \u0435\u0451 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0445\u0440\u0430\u043d\u0438\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 <code>value<\/code> \u0432 <strong>\u0441\u043e\u0441\u0435\u0434\u043d\u044e\u044e<\/strong> \u0442\u043e\u0447\u043a\u0443 <code>key<\/code>. \u042d\u0442\u043e \u0435\u0434\u0438\u043d\u0438\u0447\u043d\u044b\u0439 \u0448\u0430\u0433, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0437 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 (<code>start =&gt; key<\/code>). \u0422\u0430\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0451\u0448\u0435\u0432, \u043d\u043e \u043d\u0435\u0443\u0434\u043e\u0431\u0435\u043d \u0442\u0435\u043c, \u0447\u0442\u043e \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043f\u0443\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u0441\u043e\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442. \u0415\u0441\u043b\u0438 \u043f\u0440\u0438 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 <code>cameFrom<\/code> \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043f\u0443\u0449\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430, \u0442\u043e <code>buildPath<\/code> \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0446\u0438\u043a\u043b\u0438\u0442\u044c\u0441\u044f \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u043d\u0435\u0442 \u0432 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u043c \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438, \u043d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u044f\u043a\u043e\u0431\u044b \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u0417\u0432\u0443\u0447\u0438\u0442 \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u0442\u0440\u0430\u0448\u043d\u043e, \u043d\u043e \u044f \u0442\u0443\u0442 \u043f\u043e\u043a\u043e\u0432\u044b\u0440\u044f\u043b \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043f\u043e\u043b\u0435 \u0435\u0441\u0442\u044c \u0437\u043e\u043d\u044b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a\u0430, \u043a\u043e\u043d\u044e\u0448\u043d\u0438 (\u0432\u043e\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043c\u0438\u043d\u044b), \u0442\u0435\u043b\u0435\u043f\u043e\u0440\u0442\u044b \u0438 \u043f\u0440\u043e\u0447\u0438\u0435 \u0432\u0440\u043e\u0434\u0435 \u043a\u0430\u043a \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438, \u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0441 \u0431\u0430\u0433\u0430\u043c\u0438, \u043d\u0435\u0434\u0440\u0430 <code>cameFrom<\/code> \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u043e\u0437\u0440\u0435\u043d\u0438\u0439 \u043f\u0440\u0438 \u043f\u043e\u0447\u0442\u0438 \u043d\u0443\u043b\u0435\u0432\u044b\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u0445 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438. \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043e\u0442 \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u043c\u043e\u0436\u043d\u043e \u0438 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u0430\u0440\u0430\u0434\u0438\u0433\u043c\u0430.<\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u043d\u0430 \u043a\u043e\u0440\u043d\u044e, \u0435\u0441\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u0438\u0437 <code>start<\/code> \u0432 <code>key<\/code> \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u0433\u043e <strong>\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0439<\/strong> \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041c\u044b \u0442\u0430\u043a\u043e\u0435 \u0443\u0436\u0435 \u0434\u0435\u043b\u0430\u043b\u0438, \u043a\u043e\u0433\u0434\u0430 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u0440\u0430\u0431\u043b\u044f. \u0422\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b <code>Vector2I list<\/code> \u0432\u0438\u0434\u0430 <code>[start; ... ; key]<\/code>. \u041e\u0442\u043a\u0443\u0441\u044b\u0432\u0430\u044f \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u0443\u044e \u0433\u043e\u043b\u043e\u0432\u0443 (\u043f\u0435\u0440\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442), \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0443\u0442\u0438 \u0432 \u043e\u0441\u0442\u0430\u0442\u043a\u0435:<\/p>\n<pre><code class=\"fsharp\">match motion with | [] -&gt; ... | next :: remain -&gt; ... <\/code><\/pre>\n<p>\u041f\u0440\u0438 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0438 \u043f\u0443\u0442\u0438 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u043d\u0435 \u0437\u0430\u0431\u0438\u0440\u0430\u0442\u044c \u0433\u043e\u043b\u043e\u0432\u0443, \u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043d\u0435\u0446 \u0441\u043f\u0438\u0441\u043a\u0430:<\/p>\n<pre><code>\u043f\u0443\u0442\u044c \u0434\u043e `n + 1` = \u043f\u0443\u0442\u044c \u0434\u043e `n` + \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b `n + 1` <\/code><\/pre>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0434\u043e\u0440\u043e\u0433\u043e \u043d\u0430\u043c \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c \u0432 \u0441\u0438\u043b\u0443 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 <code>'a list<\/code>:<\/p>\n<pre><code class=\"fsharp\">\/\/ \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f `list`: type 'a List =     | Nil     | Cons of (Head : 'a) * (Tail : 'a List) <\/code><\/pre>\n<p><code>list<\/code> \u0443\u043c\u0435\u0435\u0442 \u0431\u044b\u0441\u0442\u0440\u043e \u0437\u0430 <code>O(1)<\/code> \u00ab\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u00bb \u0438 \u00ab\u0443\u0434\u0430\u043b\u044f\u0442\u044c\u00bb \u0433\u043e\u043b\u043e\u0432\u0443, \u043d\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u0430\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0441 \u0445\u0432\u043e\u0441\u0442\u043e\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0439 \u043f\u0435\u0440\u0435\u0441\u0431\u043e\u0440\u043a\u0438 \u0432\u0441\u0435\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430 <code>O(n)<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0434\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0443\u0442\u044c \u0437\u0430\u0434\u043e\u043c \u043d\u0430\u043f\u0435\u0440\u0451\u0434 (\u0440\u0435\u0447\u044c \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e \u0444\u043e\u0440\u043c\u0435 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f), \u0442\u043e\u0433\u0434\u0430 <code>key<\/code> \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0433\u043e\u043b\u043e\u0432\u0443:<\/p>\n<pre><code class=\"fsharp\">paths.[next] &lt;- next :: paths.[current] <\/code><\/pre>\n<p>\u042d\u0442\u043e \u0440\u0430\u0431\u043e\u0447\u0435\u0435, \u044f \u0431\u044b \u0434\u0430\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043b, \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u041c\u044b \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u0435\u043c \u043a \u043d\u0435\u043c\u0443 \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u0445, \u0442\u0430\u043a \u0447\u0442\u043e \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u0440\u0430\u0442\u044c \u043d\u0430 \u0432\u043e\u043e\u0440\u0443\u0436\u0435\u043d\u0438\u0435. \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u2014 \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u0442\u0430\u0434\u0438\u044f\u0445 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u0438 \u043f\u0443\u0442\u0438 \u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0438 \u0438\u0445 \u043d\u0430\u0434\u043e \u0440\u0435\u0438\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e. \u0412 \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0439\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u0445 (\u043d\u0435 \u043d\u0430\u0448 \u0441\u043b\u0443\u0447\u0430\u0439) \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0448\u0430\u043d\u0441 \u043e\u0448\u0438\u0431\u0438\u0442\u044c\u0441\u044f \u0432 \u00ab\u0447\u0451\u0442\u043d\u043e\u0441\u0442\u0438\u00bb <code>List.rev<\/code>, \u0432\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 \u0447\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 SCDU \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"fsharp\">\/\/ \u041f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442: type 'a RevList = {     AsReversedList : 'a list  }     with     member this.AsList = List.rev this.AsReversedList     static member create reversedList = { AsReversedList = reversedList }     ...  \/\/ \"\u0423\u043c\u043d\u044b\u0439\" \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0441 \u043a\u0435\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c. \/\/ `equality` \u0438 `comparison` \u043e\u0442\u0432\u0430\u043b\u044f\u0442\u0441\u044f, \/\/ \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0445 \u043d\u0430\u0434\u043e \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e. type 'a RevListCached = private {     asReversedList : 'a list     asList : 'a list Lazy }     with     member this.AsReversedList = this.asReversedList     member this.AsList = this.asList.Value     static member create reversedList = {         asReversedList = reversedList         asList = lazy(List.rev reversedList)     }     ...  <\/code><\/pre>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a\u0440\u0443\u0447\u0435, \u0435\u0441\u043b\u0438 \u0432\u0437\u044f\u0442\u044c \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0443\u043c\u0435\u044e\u0449\u0443\u044e \u0440\u0430\u0441\u0442\u0438 \u0441 \u043a\u043e\u043d\u0446\u0430. \u0412 \u043f\u0430\u043a\u0435\u0442\u0435 <code>FSharpx.Collections<\/code> \u0435\u0441\u0442\u044c <code>'a PersistentVector<\/code>. \u041e\u043d \u0432\u0435\u0434\u0451\u0442 \u0441\u0435\u0431\u044f \u043a\u0430\u043a \u043b\u0438\u043d\u0435\u0439\u043d\u0430\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f, \u043d\u043e \u043f\u043e\u0434 \u0435\u0433\u043e \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043f\u0440\u044f\u0447\u0435\u0442\u0441\u044f \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043c\u0435\u0435\u0442 \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u0451\u0448\u0435\u0432\u043e:<\/p>\n<ul>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0432 \u0441\u0432\u043e\u0439 \u043a\u043e\u043d\u0435\u0446 \u2014 <code>Conj<\/code> (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 <code>Cons<\/code>);<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0434\u0451\u0440\u0433\u0438\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u2014 <code>Initial, Last<\/code> (\u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 <code>Head, Tail<\/code>);<\/p>\n<\/li>\n<li>\n<p>\u0410 \u0442\u0430\u043a\u0436\u0435 \u00ab\u0438\u0441\u043a\u0430\u0442\u044c\u00bb \u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u043e \u0438\u043d\u0434\u0435\u043a\u0441\u0443 \u2014 <code>nth<\/code>\/\u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0442\u043e\u0440 \u0438 <code>update<\/code> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u044f\u0437\u044b\u043a\u043e\u043c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0439, \u0442\u043e \u0432 \u043d\u0430\u0440\u043e\u0434\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043e \u043c\u043d\u0435\u043d\u0438\u0435, \u0447\u0442\u043e <code>list<\/code> \u2014 \u044d\u0442\u043e \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442 <code>Stack<\/code>, \u0430 <code>PersistentVector<\/code> \u2014 \u0438\u043c\u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442 <code>ResizeArray<\/code> (<code>List<\/code> \u0432 C#).<\/p>\n<p><code>'a PersistentVector<\/code> \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f <code>cameFrom<\/code>, \u043d\u043e \u0438 \u0434\u043b\u044f \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0435\u0439 <code>costSoFar<\/code>. \u041e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u043d\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0435\u0451 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u0435\u043d \u0434\u043e \u0442\u0430\u043a\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438, \u0447\u0442\u043e \u043e\u0431\u0435 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0438\u0442\u044c \u0432 \u043e\u0434\u043d\u0443, \u0435\u0441\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 <code>'a<\/code> \u0432\u0437\u044f\u0442\u044c \u0442\u0443\u043f\u043b \u0438\u043b\u0438 \u0440\u0435\u043a\u043e\u0440\u0434:<\/p>\n<pre><code class=\"fsharp\">let tryFindPath mapSize isObstacle start goal =     if not ^ inMap mapSize goal then Result.Error OutOfBounds     elif isObstacle goal then Result.Error Obstacle else     let frontier = PriorityStack.singleton 0 start     \/\/ \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438:     let createStep position cost = {|         Position = position         Cost = cost     |}     let paths =         createStep start 0         |&gt; PersistentVector.singleton         |&gt; Dictionary.singleton start      let rec tryFind () =         match frontier.TryTake () with         | None -&gt; Result.Error Unreachable         | Some (Eq goal) -&gt;             Ok {|                 Path = paths.[goal]                 Cost = paths.[goal].Last.Cost                 Goal = goal                 Start = start                 Paths = paths.AsReadOnly()                 Frontier = List.ofSeq ^ frontier.AsSeq()             |}         | Some current -&gt;             let currentPath = paths.[current]             let newCost = currentPath.Last.Cost + 1             for next in neighbours mapSize isObstacle current do                 match paths.TryGetValue next with                 | true, PersistentVector.Conj (_, old) when newCost &gt;= old.Cost -&gt; ()                 | _ -&gt;                     frontier.Put (newCost + heuristic goal next) next                     paths.[next] &lt;- currentPath.Conj ^ createStep next newCost             tryFind ()     tryFind () <\/code><\/pre>\n<p>\u0412 \u043a\u0430\u0436\u0434\u043e\u043c <code>paths.[key]<\/code> \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f <code>PersistentVector<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430:<\/p>\n<pre><code class=\"fsharp\">{| Position = start; Cost = 0 |} {| Position = \u0441\u043e\u0441\u0435\u0434 start; Cost = 1 |} ... {| Position = \u0441\u043e\u0441\u0435\u0434 key; Cost = finalCost - 1 |} {| Position = key; Cost = finalCost |} <\/code><\/pre>\n<p>\u0412\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u0442\u043e\u0447\u043a\u0443 \u0441\u0442\u0430\u0440\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0440\u0430\u043d\u044c\u0448\u0435 <code>buildPath<\/code> \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b. \u042d\u0442\u043e \u043d\u0435 \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0439 \u044d\u0444\u0444\u0435\u043a\u0442 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043d\u0430 <code>PersistentVector<\/code>, \u0430 \u0441\u043e\u0437\u043d\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435. \u041c\u043d\u0435 \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u043d\u0430 \u0440\u0443\u043a\u0443, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u0447\u0438\u043d\u0430\u043b <code>paths<\/code> \u0441 <code>singleton<\/code>. \u0415\u0441\u043b\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u043d\u0435\u0433\u043e \u0432\u0437\u044f\u0442\u044c <code>PersistentVector.empty<\/code>, \u043f\u0443\u0442\u0438 \u043f\u0440\u0438\u043e\u0431\u0440\u0435\u0442\u0443\u0442 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0443\u044e \u00ab\u0431\u0435\u0437\u0433\u043e\u043b\u043e\u0432\u0443\u044e\u00bb \u0444\u043e\u0440\u043c\u0443.<\/p>\n<p>\u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0432 \u044d\u0442\u0438\u0445 \u00ab\u043f\u0440\u0430\u0432\u0438\u043b\u0430\u0445 \u0438\u0433\u0440\u044b\u00bb \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u043b\u0435\u0442\u043e\u043a \u0441\u043e \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043e\u0442\u043b\u0438\u0447\u043d\u043e\u0439 \u043e\u0442 \u043d\u0443\u043b\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 <code>Cost<\/code> \u0437\u0434\u0435\u0441\u044c \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0442\u044c \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c \u0441\u0432\u043e\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430. <code>Cost<\/code> \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u043f\u0443\u0442\u0438, \u0438 \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043a\u0430\u043a <code>persistentVector.Length - 1<\/code>. \u042d\u0442\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u043e\u0438\u0442\u044c <code>O(1)<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a <code>PersistentVector<\/code> \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u0432\u043e\u044e \u0434\u043b\u0438\u043d\u0443 \u0432 \u0433\u043e\u0442\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0435 (\u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 <code>list<\/code>). \u041e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044f\u0441\u044c \u043d\u0430 \u044d\u0442\u043e\u043c, \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u0440\u0435\u043a\u043e\u0440\u0434\u0430 \u0432 \u043f\u043e\u043b\u044c\u0437\u0443 <code>Vector2I<\/code> (<code>Vector2I PersistentVector<\/code>).<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u044f \u0442\u0430\u043a \u043d\u0435 \u0434\u0435\u043b\u0430\u044e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u043b\u0430\u043d\u0434\u0448\u0430\u0444\u0442\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0440\u0435\u043a\u043e\u0440\u0434\u0430\u0445 \u043c\u043e\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u043e \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 (\u0442. \u0435. \u0434\u0435\u043b\u044c\u0442\u0443) \u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0435 \u0434\u0440\u0443\u0433\u043e\u0435 \u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0442\u0438\u043f\u0430 \u00ab\u043f\u043e\u043f\u0430\u043b \u0432 \u0437\u043e\u043d\u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0432\u0440\u0430\u0433\u0430\u00bb \u0438 \u0442. \u0434.<\/p>\n<p><em>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u043e\u0442\u0432\u0430\u0434\u0438\u0442\u044c \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0435\u0439 \u043e\u0442 \u0437\u0430\u043f\u0438\u0445\u0438\u0432\u0430\u043d\u0438\u044f \u0432 \u0440\u0435\u043a\u043e\u0440\u0434 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0435\u0439\u0441\u044f \u043a \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u0443\u0442\u0438, \u043d\u043e \u043c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u043a\u0438\u0434\u0430\u043b\u0438 \u0446\u0435\u043b\u0443\u044e \u043f\u0430\u043d\u0430\u043c\u043a\u0443 \u043a\u0435\u0439\u0441\u043e\u0432 (\u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043c\u043e\u0438\u0445 \u0436\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u043a\u0430\u043f\u0443\u0441\u0442\u043d\u0438\u043a\u0430\u0445), \u0433\u0434\u0435 \u044d\u0442\u043e\u0442 \u043a\u0440\u0438\u0442\u0435\u0440\u0438\u0439 \u043e\u0449\u0443\u0442\u0438\u043c\u043e \u0432\u0440\u0435\u0434\u0438\u043b \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u0443, \u0438 \u0438\u0433\u0440\u043e\u043a\u0443.<\/em> <em>\u0422\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u0437\u0430\u043f\u0438\u0445\u0438\u0432\u0430\u0442\u044c \u0442\u0443\u0434\u0430 \u0447\u0442\u043e \u0443\u0433\u043e\u0434\u043d\u043e, \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0435\u0442\u0435, \u0437\u0430\u0447\u0435\u043c.<\/em><\/p>\n<h3>\u041c\u043d\u043e\u0433\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0439 \u043f\u043e\u0438\u0441\u043a \u043f\u0443\u0442\u0438<\/h3>\n<p><code>PersistentVector<\/code> \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0424\u041f-\u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432, \u043d\u043e \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043f\u0440\u0438\u0448\u0451\u043b\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043a \u043c\u0435\u0441\u0442\u0443, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0431\u044b\u043b\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439 \u0441 \u043e\u0431\u0449\u0438\u043c \u0433\u0435\u043d\u0435\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0440\u043e\u0448\u043b\u044b\u043c. \u0427\u0438\u0441\u0442\u043e \u0438\u0437 <strong>\u0441\u043f\u043e\u0440\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0430<\/strong> \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0437\u044b\u0433\u0440\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0443 \u0440\u043e\u0434\u0441\u0442\u0432\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e, \u0435\u0441\u043b\u0438 \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0451\u043c \u043d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u043e\u0434\u043d\u043e\u0439 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0434\u0440\u0443\u0433\u0443\u044e. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0434\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u043f\u043e\u0434\u043b\u0435\u0436\u0430\u0442 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0443.<\/p>\n<p>\u0425\u0443\u0436\u0435 \u0432\u0441\u0435\u0433\u043e<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-467886","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/467886","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=467886"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/467886\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=467886"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=467886"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=467886"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}