{"id":437641,"date":"2024-11-07T21:02:41","date_gmt":"2024-11-07T21:02:41","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=437641"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=437641","title":{"rendered":"<span>\u0410\u0437\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0441 ChatGPT<\/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<p>\u042f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0430\u043c\u0438 \u043e\u043f\u044b\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f &#171;\u0441 \u043d\u0443\u043b\u044f&#187;  iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 \u0438\u0433\u0440\u044b 2048 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0418\u0418 (\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0430) \u0432 SwiftUI \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ChatGPT .<\/p>\n<p>\u0412 \u0441\u0432\u043e\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u0438\u0433\u0440\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0436\u0435\u0441\u0442\u043e\u0432 (\u0432\u0432\u0435\u0440\u0445, \u0432\u043d\u0438\u0437, \u0432\u043f\u0440\u0430\u0432\u043e, \u0432\u043b\u0435\u0432\u043e),\u00a0 \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0438\u0433\u0440\u0430 \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0439 \u0438\u0433\u0440\u044b 2048 \u043c\u043e\u0436\u043d\u043e \u0437\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c\u00a0 \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u0435\u043d \u043a\u0430\u0436\u0434\u043e\u043c\u0443. \u041d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438\u0433\u0440\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048, \u0442\u043e \u0435\u0441\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0418\u0418, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0433 \u0431\u044b \u0438\u0433\u0440\u0430\u0442\u044c \u0432 \u044d\u0442\u0443 \u0438\u0433\u0440\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0447\u0435\u0442 \u0438\u0433\u0440\u044b \u0432 \u0440\u0430\u0437\u0443\u043c\u043d\u044b\u0435 \u0441\u0440\u043e\u043a\u0438. <\/p>\n<p>\u041c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u0433\u0440\u0443 2048 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 SwiftUI, \u043f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u0435\u0433\u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0438 \u043c\u043e\u0449\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0438 \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u044b\u043c \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u043c , a \u0442\u0430\u043a\u0436\u0435\u00a0 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u201c\u0440\u0443\u0447\u043d\u043e\u0439\u201d \u0441\u043f\u043e\u0441\u043e\u0431 \u0438\u0433\u0440\u044b, \u043a\u043e\u0433\u0434\u0430 \u0412\u044b \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435 \u0442\u0435\u043c, \u043a\u0430\u043a\u0438\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0445\u043e\u0434: \u0432\u0432\u0435\u0440\u0445, \u0432\u043d\u0438\u0437, \u0432\u043b\u0435\u0432\u043e \u0438 \u0432\u043f\u0440\u0430\u0432\u043e, \u043d\u043e \u0438 \u0440\u044f\u0434 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0441 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0435\u0439 (<a href=\"https:\/\/habr.com\/ru\/companies\/edison\/articles\/437118\/\" rel=\"noopener noreferrer nofollow\">\u043c\u0435\u0442\u043e\u0434\u0430 \u041c\u043e\u043d\u0442\u0435-\u041a\u0430\u0440\u043b\u043e<\/a>,\u00a0<a href=\"https:\/\/habr.com\/ru\/companies\/edison\/articles\/474680\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c (Minimax, Expectimax<\/a>) ), \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0445 \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0445\u043e\u0434\u044b &#8212; \u0432\u0432\u0435\u0440\u0445, \u0432\u043d\u0438\u0437, \u0432\u043b\u0435\u0432\u043e \u0438 \u0432\u043f\u0440\u0430\u0432\u043e &#8212; \u0438 \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f\u00a0 \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 2048 \u0438 \u0431\u043e\u043b\u0435\u0435 (\u044d\u0442\u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u043c\u0438 \u201c\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0430\u201d (\u0418\u0418)).\u00a0\u00a0\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0418\u0418 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u043f\u0435\u0440\u0435\u0434 \u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0445\u043e\u0434 \u043e\u043d \u0445\u043e\u0447\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438.  <\/p>\n<p>2048 &#8212; \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u0438\u0433\u0440\u0430, \u0438 \u043c\u043d\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c ChatGPT \u0435\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u043e\u043d \u0441\u0430\u043c \u0432\u0441\u0451 \u043f\u0440\u043e \u043d\u0435\u0451 \u0437\u043d\u0430\u0435\u0442. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e ChatGPT \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d \u043e\u0431 \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u0445 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043d\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c ChatGPT \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0435\u0448\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438. \u0418 \u043e\u043d \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b \u043c\u043d\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0438\u0445 \u043d\u0435\u043e\u0440\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0434\u043e\u043b\u0433\u043e \u0432\u044b\u0438\u0441\u043a\u0438\u0432\u0430\u0442\u044c \u0432 \u043d\u0430\u0443\u0447\u043d\u044b\u0445 \u0436\u0443\u0440\u043d\u0430\u043b\u0430\u0445.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u044b \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0441\u043c\u043e\u0433\u043b\u0438 \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u044f \u043a\u0440\u0430\u0442\u043a\u043e \u043d\u0430\u043f\u043e\u043c\u043d\u044e \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438\u0433\u0440\u044b 2048.<\/p>\n<p>\u0421\u0430\u043c\u0430 \u0438\u0433\u0440\u0430 \u043f\u0440\u043e\u0441\u0442\u0430. \u0412\u0430\u043c \u0434\u0430\u0435\u0442\u0441\u044f \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c\u00a0<strong>4<\/strong>\u00d7<strong>4<\/strong>, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0447\u0438\u0441\u043b\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f.\u00a0<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2e5\/f80\/f04\/2e5f80f047f3d61240ad09139f6846e4.png\" alt=\"\u0420\u0438\u0441.1 \u041f\u0440\u0438\u043c\u0435\u0440 \u0445\u043e\u0434\u0430 \u0432 2048. \u041f\u043e\u0441\u043b\u0435 \u0445\u043e\u0434\u0430 \u201c\u0441\u0434\u0432\u0438\u0433 \u0432\u043b\u0435\u0432\u043e\u201d (left) \u043d\u0430 \u043b\u0435\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435. \u0414\u043e\u0441\u043a\u0430 \u0441\u043b\u0435\u0432\u0430 \u0441\u0442\u0430\u043d\u0435\u0442 \u0442\u043e\u0439, \u0447\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u0440\u0438\u0441. \u0441\u043f\u0440\u0430\u0432\u0430.\" title=\"\u0420\u0438\u0441.1 \u041f\u0440\u0438\u043c\u0435\u0440 \u0445\u043e\u0434\u0430 \u0432 2048. \u041f\u043e\u0441\u043b\u0435 \u0445\u043e\u0434\u0430 \u201c\u0441\u0434\u0432\u0438\u0433 \u0432\u043b\u0435\u0432\u043e\u201d (left) \u043d\u0430 \u043b\u0435\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435. \u0414\u043e\u0441\u043a\u0430 \u0441\u043b\u0435\u0432\u0430 \u0441\u0442\u0430\u043d\u0435\u0442 \u0442\u043e\u0439, \u0447\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u0440\u0438\u0441. \u0441\u043f\u0440\u0430\u0432\u0430.\" width=\"1498\" height=\"748\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2e5\/f80\/f04\/2e5f80f047f3d61240ad09139f6846e4.png\"\/><\/p>\n<div><figcaption>\u0420\u0438\u0441.1 \u041f\u0440\u0438\u043c\u0435\u0440 \u0445\u043e\u0434\u0430 \u0432 2048. \u041f\u043e\u0441\u043b\u0435 \u0445\u043e\u0434\u0430 \u201c\u0441\u0434\u0432\u0438\u0433 \u0432\u043b\u0435\u0432\u043e\u201d (left) \u043d\u0430 \u043b\u0435\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435. \u0414\u043e\u0441\u043a\u0430 \u0441\u043b\u0435\u0432\u0430 \u0441\u0442\u0430\u043d\u0435\u0442 \u0442\u043e\u0439, \u0447\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u0440\u0438\u0441. \u0441\u043f\u0440\u0430\u0432\u0430.<\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0438\u0441\u043b\u0430 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0441\u0442\u0435\u043f\u0435\u043d\u044c\u044e \u0434\u0432\u043e\u0439\u043a\u0438. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u043d\u043e\u043c\u0435\u0440\u0430\u043c\u0438\u00a0<strong>2<\/strong>\u00a0\u0438\u043b\u0438\u00a0<strong>4<\/strong>. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435, \u043d\u0430\u0436\u0438\u043c\u0430\u044f \u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 \u0441\u043e \u0441\u0442\u0440\u0435\u043b\u043a\u0430\u043c\u0438 &#8212;<strong>\u00a0\u0432\u0432\u0435\u0440\u0445<\/strong>,<strong>\u00a0\u0432\u043d\u0438\u0437<\/strong>,\u00a0<strong>\u0432\u043f\u0440\u0430\u0432\u043e<\/strong>,\u00a0<strong>\u0432\u043b\u0435\u0432\u043e<\/strong>\u00a0&#8212; \u0438 \u0432\u0441\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438, \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043b\u0438\u0442\u043a\u043e\u0439, \u043b\u0438\u0431\u043e \u0433\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u0441\u0435\u0442\u043a\u0438. \u0415\u0441\u043b\u0438 \u0434\u0432\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u0447\u0438\u0441\u043b\u0430\u043c\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f, \u043e\u043d\u0438 \u0441\u043e\u043b\u044c\u044e\u0442\u0441\u044f \u0432 \u043d\u043e\u0432\u0443\u044e \u043f\u043b\u0438\u0442\u043a\u0443 \u0441 \u0438\u0445 \u0441\u0443\u043c\u043c\u043e\u0439. \u041d\u043e\u0432\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0441\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u043f\u043b\u0438\u0442\u043a\u043e\u0439 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f. \u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 2 \u0438\u043b\u0438 4 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u043f\u0443\u0441\u0442\u044b\u0445 \u043f\u043b\u0438\u0442\u043e\u043a, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0438\u0433\u0440\u043e\u043a \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u0445\u043e\u0434.<\/p>\n<p>\u0426\u0435\u043b\u044c \u0438\u0433\u0440\u044b \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0441\u0442\u0438\u0447\u044c \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 2048, \u043d\u043e \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0448\u0438\u0440\u043e\u043a\u043e \u0438 \u0434\u043e\u0441\u0442\u0438\u0433\u0430\u0442\u044c \u043f\u043b\u0438\u0442\u043a\u0443 \u0441 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0447\u0438\u0441\u043b\u043e\u043c. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u043e\u0447\u043a\u043e\u0432, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c\u0430\u044f \u043a \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0445\u043e\u0434\u0443. \u0421\u0447\u0435\u0442 \u0438\u0433\u0440\u043e\u043a\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0434\u0432\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f, \u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u043e\u0439 \u043f\u043b\u0438\u0442\u043a\u0438. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u043f\u0443\u0441\u0442\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0445 \u0445\u043e\u0434\u043e\u0432, \u0442\u043e \u0438\u0433\u0440\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.\u00a0<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043c\u043e\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0430\u0441\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u0432\u0438\u0436\u043e\u043a \u0438\u0433\u0440\u044b 2048 \u043d\u0430 Swift, \u043d\u043e \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c UI c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SwiftUI, a \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0418\u0418 (\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b Expectimax \u0438 Monte Carlo) \u0432 \u0438\u0433\u0440\u0435 2048. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u044f \u0445\u043e\u0442\u0435\u043b\u0430 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 ChatGPT.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0430\u043f\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0430\u043a\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ChatGPT:<\/p>\n<ol>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b \u0431\u0435\u0437 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 UI (\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u043f\u043b\u0438\u0442\u043e\u043a, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 AI (\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b Greedy, Expectimax \u0438 MonteCarlo) \u0432 \u0438\u0433\u0440\u0443 2048 c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c.<\/p>\n<p>\u041d\u0430 \u0442\u0440\u0435\u0442\u044c\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u044f  \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430 \u043e\u0442 ChatGPT  \u0434\u0432\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0418\u0418 &#8212;\u00a0<strong>Expectimax<\/strong>\u00a0\u0438\u00a0<strong>Monte Carlo<\/strong>\u00a0&#8212; \u0438 \u0438\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b &#8212; \u043f\u043b\u0438\u0442\u043a\u0438 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438\u00a0\u00a0<strong>4096<\/strong>\u00a0\u0438\u00a0<strong>8092<\/strong>.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d88\/19b\/8c1\/d8819b8c159273d16dc93808c35bbf33.gif\" alt=\"\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Expectimax \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438\" title=\"\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Expectimax \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438\" width=\"364\" height=\"740\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d88\/19b\/8c1\/d8819b8c159273d16dc93808c35bbf33.gif\"\/><\/p>\n<div><figcaption>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Expectimax \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<\/li>\n<\/ol>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/75e\/e10\/be4\/75ee10be48d6516a9a3d13a93418ac5d.gif\" alt=\"\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Monte Carlo \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\" title=\"\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Monte Carlo \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\" width=\"374\" height=\"718\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/75e\/e10\/be4\/75ee10be48d6516a9a3d13a93418ac5d.gif\"\/><\/p>\n<div><figcaption>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Monte Carlo \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438<\/figcaption><\/div>\n<\/figure>\n<p>\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u043a\u0430\u043a\u043e\u0439 \u0440\u0430\u0437\u043d\u044b\u0439 \u0440\u0438\u0441\u0443\u043d\u043e\u043a \u0438\u0433\u0440\u044b \u0443 \u044d\u0442\u0438\u0445 \u0434\u0432\u0443\u0445 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432, \u0441\u0442\u0440\u0435\u043c\u044f\u0449\u0438\u0445\u0441\u044f \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u0442\u043e\u043c\u0443 \u0436\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0443.<\/p>\n<p>\u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e ChatGPT 4-o.mini (\u043d\u0435 \u0441\u0430\u043c\u0443\u044e \u043c\u043e\u0449\u043d\u0443\u044e). \u0412\u0441\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0434\u0430\u0432\u0430\u043b\u0438\u0441\u044c \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u043e\u0442 ChatGPT 4-o.mini \u0442\u043e\u0436\u0435 \u0431\u044b\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c, \u043d\u043e \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u044b \u0441\u0430\u043c\u0438\u043c \u0436\u0435 ChatGPT \u0434\u043b\u044f \u0432\u0430\u0441 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u0438\u0439.\u00a0<\/p>\n<p>\u0412 \u043f\u043b\u0430\u043d\u0435 \u0434\u0432\u0438\u0436\u043a\u0430 \u0438\u0433\u0440\u044b 2048 \u0438 UI \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 ChatGPT \u0434\u0430\u043b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0441 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u0445\u043e\u0442\u044f \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0435 \u043e\u0431\u043e\u0448\u043b\u043e\u0441\u044c. \u0423 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e \u043e\u0448\u0438\u0431\u043e\u043a, \u043d\u043e \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u0437\u0430\u0432\u0443\u0430\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0442\u0430\u043a-\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0439\u0442\u0438. \u0412\u043e\u0442 \u0442\u043e\u0433\u0434\u0430 \u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u0442\u044c \u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 ChatGPT \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e. <\/p>\n<p>\u0412 \u043f\u043b\u0430\u043d\u0435 \u0418\u0418 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048 ChatGPT \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0440\u0430\u0437\u0438\u043b \u043c\u0435\u043d\u044f \u0441\u0432\u043e\u0435\u0439 \u044d\u0440\u0443\u0434\u0438\u0446\u0438\u0435\u0439, \u043e\u043d \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u043b \u043c\u043d\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u0442\u0430\u043a\u0438\u0435  \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b, \u043a\u0430\u043a Expextimax \u0438 Monte Carlo \u0441\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0437\u043d\u0430\u0447\u0438\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430. \u0418 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0432\u0435\u0442\u044b, \u0432\u0441\u0435 \u044d\u0442\u043e \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Swift \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438 \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0445 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0438\u0433\u0440\u0435 2048.  <\/p>\n<p>\u0415\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u0446\u0435\u043d\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043c\u043e\u0436\u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043d\u0430 Swift \u0438 SwiftUI \u043d\u0435 \u0445\u0443\u0436\u0435 <a href=\"https:\/\/bestkora.com\/IosDeveloper\/ios-swiftui-2023\/\" rel=\"noopener noreferrer nofollow\">\u0421\u0442\u044d\u043d\u0444\u043e\u0440\u0434\u0441\u043a\u043e\u0433\u043e \u043a\u0443\u0440\u0441\u0430<\/a>. <\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 ChatGPT \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 iOS  \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 3-\u0445 \u043f\u043e\u0441\u0442\u0430\u0445 \u043d\u0430 \u043c\u043e\u0435\u043c \u0441\u0430\u0439\u0442\u0435: <\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/bestkora.com\/IosDeveloper\/test\/%E2%86%97\" rel=\"noopener noreferrer nofollow\">iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0432 SwiftUI\u00a0 \u0441 ChatGPT 4-o. \u0427\u0430\u0441\u0442\u044c 1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435. \u041b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b 2048.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/bestkora.com\/IosDeveloper\/%D0%B0%D0%B7%D0%B0%D1%80%D1%82%D0%BD%D0%B0%D1%8F-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-ios-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8%D0%B3%D1%80%D1%8B\/%E2%86%97\" rel=\"noopener noreferrer nofollow\">iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0432 SwiftUI\u00a0 \u0441 ChatGPT 4-o. \u0427\u0430\u0441\u0442\u044c 2. \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0438 UI.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/bestkora.com\/IosDeveloper\/ios-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8%D0%B3%D1%80%D1%8B-2048-%D0%B2-swiftui-%D1%81-chatgpt-%D1%87%D0%B0%D1%81%D1%82%D1%8C-3-%D0%B8%D0%B8-ai\/\" rel=\"noopener noreferrer nofollow\">iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b 2048 \u0432 SwiftUI \u0441 ChatGPT. \u0427\u0430\u0441\u0442\u044c 3. \u0418\u0418 (AI) \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048.<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0410 \u043a\u043e\u0434 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/Game2048ChatGPT\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u043b\u0438\u0448\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430, \u0447\u0442\u043e\u0431\u044b \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u043f\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c ChatGPT \u043a\u0430\u043a \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438.<\/p>\n<h2>\u041b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b 2048<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a ChatGPT:<\/p>\n<h3>\u0428\u0410\u0413 1. \u041d\u0430\u0447\u0430\u043b\u043e<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/321\/bae\/66d\/321bae66d996a2483a3c91f8e53f98be.png\" width=\"1024\" height=\"246\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/321\/bae\/66d\/321bae66d996a2483a3c91f8e53f98be.png\"\/><\/figure>\n<div class=\"floating-image\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b01\/33a\/ded\/b0133adedd7eb0460a43fb66038bb007.png\" width=\"1412\" height=\"562\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b01\/33a\/ded\/b0133adedd7eb0460a43fb66038bb007.png\"\/><\/figure>\n<\/div>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameViwModel<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  enum Direction {     case up, down, left, right }  class GameViewModel: ObservableObject {     @Published var board: [[Int]]     @Published var gameOver = false      init() {         board = Array(repeating: Array(repeating: 0, count: 4), count: 4)         addNewTile()         addNewTile()     }      func addNewTile() {         var emptyTiles: [(Int, Int)] = []         for row in 0..&lt;4 {             for col in 0..&lt;4 {                 if board[row][col] == 0 {                     emptyTiles.append((row, col))                 }             }         }         if let randomTile = emptyTiles.randomElement() {             board[randomTile.0][randomTile.1] = Bool.random() ? 2 : 4         }     }          func resetGame(_ direction: Direction) {         \/\/ Reset the board to the initial state         board = Array(repeating: Array(repeating: 0, count: 4), count: 4)         gameOver = false         addNewTile()         addNewTile()      }      func move(_ direction: Direction) {         \/\/ Implement the movement logic here         \/\/ This will include merging tiles and updating the board state         \/\/ After moving tiles, call addNewTile() to add a new tile     }      func checkGameOver() {         \/\/ Implement the logic to check if the game is over         \/\/ This will involve checking if there are any valid moves left     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/956\/8d6\/603\/9568d6603181615564cad8aa5362aaa8.png\" width=\"1024\" height=\"184\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/956\/8d6\/603\/9568d6603181615564cad8aa5362aaa8.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameView<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct GameView: View {     @StateObject private var viewModel = GameViewModel()      var body: some View {         VStack {             Text(\"2048\")                 .font(.largeTitle)                 .padding()                          GridView(board: viewModel.board)                 .padding()                          Button(action: {                 \/\/ Implement restart functionality                 viewModel = GameViewModel()             }) {                 Text(\"Restart\")                     .font(.title)                     .padding()             }         }         .onAppear {             \/\/ Initialize game state         }         .onReceive(NotificationCenter.default.publisher(for:                           UIResponder.keyboardWillShowNotification)) { _ in             \/\/ Handle keyboard events or gestures here         }     } }  struct GridView: View {     let board: [[Int]]      var body: some View {         VStack(spacing: 8) {             ForEach(0..&lt;4) { row in                 HStack(spacing: 8) {                     ForEach(0..&lt;4) { col in                         TileView(value: board[row][col])                     }                 }             }         }     } }  struct TileView: View {     let value: Int      var body: some View {         Text(value == 0 ? \"\" : \"\\(value)\")             .frame(width: 80, height: 80)             .background(Color.gray.opacity(0.4))             .cornerRadius(10)             .font(.title)             .foregroundColor(.black)     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5e2\/18c\/f51\/5e218cf514d8b0ede7befd2f03b497cc.png\" width=\"1024\" height=\"153\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5e2\/18c\/f51\/5e218cf514d8b0ede7befd2f03b497cc.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameView \u0441 \u0436\u0435\u0441\u0442\u043e\u043c DragGesture<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct GameView: View {     @StateObject private var viewModel = GameViewModel()      var body: some View {         VStack {             Text(\"2048\")                 .font(.largeTitle)                 .padding()                          GridView(board: viewModel.board)                 .padding()                 .gesture(                     DragGesture()                         .onEnded { value in                             let horizontalAmount = value.translation.width                             let verticalAmount = value.translation.height                                                          if abs(horizontalAmount) &gt; abs(verticalAmount) {                                 if horizontalAmount &gt; 0 {                                     viewModel.move(.right)                                 } else {                                     viewModel.move(.left)                                 }                             } else {                                 if verticalAmount &gt; 0 {                                     viewModel.move(.down)                                 } else {                                     viewModel.move(.up)                                 }                             }                         }                 )                          Button(action: {                 viewModel = viewModel.resetGame()              }) {                 Text(\"Restart\")                     .font(.title)                     .padding()             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/424\/c31\/f88\/424c31f88a56b0e10ebc6aade57b46dc.png\" width=\"1024\" height=\"401\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/424\/c31\/f88\/424c31f88a56b0e10ebc6aade57b46dc.png\"\/><\/figure>\n<p>\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 Xcode:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1ff\/343\/d0f\/1ff343d0fd7c14bc90233cefe94acee3.gif\" width=\"540\" height=\"498\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1ff\/343\/d0f\/1ff343d0fd7c14bc90233cefe94acee3.gif\"\/><\/figure>\n<p>\u041c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0432\u043f\u043e\u043b\u043d\u0435 \u0441\u0435\u0431\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 UI \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u201c\u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0430\u043c\u0438\u201d \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0433\u0440\u044b 2048, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u0434\u043e\u043c.\u00a0<\/p>\n<h2>\u0428\u0410\u0413 2. \u0424\u0443\u043d\u043a\u0446\u0438\u044f\u00a0move()<\/h2>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u043a\u043e\u0434 \u0434\u043b\u044f \u0441\u0430\u043c\u043e\u0439 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<strong>\u00a0<\/strong><code>move()<\/code>\u00a0\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e CharGPT:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/764\/7ec\/b76\/7647ecb76ca0d4d18275a82922cc913c.png\" width=\"1024\" height=\"164\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/764\/7ec\/b76\/7647ecb76ca0d4d18275a82922cc913c.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6a4\/d7e\/e39\/6a4d7ee39ae07935298e7d1c90003f21.png\" width=\"1024\" height=\"313\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6a4\/d7e\/e39\/6a4d7ee39ae07935298e7d1c90003f21.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0424\u0443\u043d\u043a\u0446\u0438\u044f move (_ direction:Direction)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func move(_ direction: Direction) {     var moved = false      \/\/ Rotate the board so that we can treat each move as if it's a \"left\" move     switch direction {     case .up:         rotateLeft()     case .down:         rotateRight()     case .right:         rotateRight()         rotateRight()     case .left:         break     }      for i in 0..&lt;4 {         let compressedRow = compressRow(board[i])         let mergedRow = mergeRow(compressedRow)         let finalRow = compressRow(mergedRow)         if finalRow != board[i] {             moved = true         }          board[i] = finalRow     }      \/\/ Rotate the board back to its original orientation     switch direction {     case .up:         rotateRight()     case .down:         rotateLeft()     case .right:         rotateRight()         rotateRight()     case .left:         break     }      if moved {         addNewTile()         checkGameOver()     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/541\/f1d\/393\/541f1d393644fa8ee4043ff2cc5c1302.png\" width=\"1024\" height=\"333\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/541\/f1d\/393\/541f1d393644fa8ee4043ff2cc5c1302.png\"\/><\/figure>\n<pre><code class=\"swift\">func rotateLeft() {     board = (0..&lt;4).map { i in         (0..&lt;4).map { j in             board[j][3 - i]         }     } }  func rotateRight() {     board = (0..&lt;4).map { i in         (0..&lt;4).map { j in             board[3 - j][i]         }     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a07\/e27\/d70\/a07e27d701e34973c67845f07665dc3c.png\" width=\"1024\" height=\"68\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a07\/e27\/d70\/a07e27d701e34973c67845f07665dc3c.png\"\/><\/figure>\n<pre><code class=\"swift\">func compressRow(_ row: [Int]) -&gt; [Int] {     let filteredRow = row.filter { $0 != 0 }     let zeros = Array(repeating: 0, count: 4 - filteredRow.count)     return filteredRow + zeros }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a1d\/5a1\/db4\/a1d5a1db40afaea37188c04353999af4.png\" width=\"1024\" height=\"103\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a1d\/5a1\/db4\/a1d5a1db40afaea37188c04353999af4.png\"\/><\/figure>\n<pre><code class=\"swift\">func mergeRow(_ row: [Int]) -&gt; [Int] {     var newRow = row     for i in 0..&lt;3 {         if newRow[i] != 0 &amp;&amp; newRow[i] == newRow[i + 1] {             newRow[i] *= 2             newRow[i + 1] = 0         }     }     return newRow }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ca4\/fe3\/246\/ca4fe3246ccae7f4cf4331e5a1dd677b.png\" width=\"1024\" height=\"390\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ca4\/fe3\/246\/ca4fe3246ccae7f4cf4331e5a1dd677b.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/360\/8c2\/11a\/3608c211a4e6250624cdfeb4ce03bb92.png\" width=\"1024\" height=\"425\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/360\/8c2\/11a\/3608c211a4e6250624cdfeb4ce03bb92.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0b5\/287\/fe3\/0b5287fe3c30ff71be57b2357e52f226.png\" width=\"1024\" height=\"263\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0b5\/287\/fe3\/0b5287fe3c30ff71be57b2357e52f226.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/138\/e91\/706\/138e91706be6c537165c2cf91e0ae4a0.png\" width=\"1024\" height=\"142\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/138\/e91\/706\/138e91706be6c537165c2cf91e0ae4a0.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u041d\u043e\u0432\u044b\u0439 GameViewModel:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">enum Direction {     case up, down, left, right }  class GameViewModel: ObservableObject {     @Published var board: [[Int]]     @Published var isGameOver = false      init() {         board = Array(repeating: Array(repeating: 0, count: 4), count: 4)         addNewTile()         addNewTile()     }      func addNewTile() {         var emptyTiles: [(Int, Int)] = []         for row in 0..&lt;4 {             for col in 0..&lt;4 {                 if board[row][col] == 0 {                     emptyTiles.append((row, col))                 }             }         }         if let randomTile = emptyTiles.randomElement() {             board[randomTile.0][randomTile.1] = Bool.random() ? 2 : 4         }     }      func move(_ direction: Direction) {         var moved = false          switch direction {         case .up:             rotateLeft()         case .down:             rotateRight()         case .right:             rotateRight()             rotateRight()         case .left:             break         }          for i in 0..&lt;4 {             let compressedRow = compressRow(board[i])             let mergedRow = mergeRow(compressedRow)             let finalRow = compressRow(mergedRow)             if finalRow != board[i] {                 moved = true             }             board[i] = finalRow         }          switch direction {         case .up:             rotateRight()         case .down:             rotateLeft()         case .right:             rotateRight()             rotateRight()         case .left:             break         }          if moved {             addNewTile()             checkGameOver()         }     }      func checkGameOver() {         \/\/ Implement the logic to check if the game is over         \/\/ This will involve checking if there are any valid moves left     }      func resetGame() {         board = Array(repeating: Array(repeating: 0, count: 4), count: 4)         gameOver = false         addNewTile()         addNewTile()     }      private func rotateLeft() {         board = (0..&lt;4).map { i in             (0..&lt;4).map { j in                 board[j][3 - i]             }         }     }      private func rotateRight() {         board = (0..&lt;4).map { i in             (0..&lt;4).map { j in                 board[3 - j][i]             }         }     }      private func compressRow(_ row: [Int]) -&gt; [Int] {         let filteredRow = row.filter { $0 != 0 }         let zeros = Array(repeating: 0, count: 4 - filteredRow.count)         return filteredRow + zeros     }      private func mergeRow(_ row: [Int]) -&gt; [Int] {         var newRow = row         for i in 0..&lt;3 {             if newRow[i] != 0 &amp;&amp; newRow[i] == newRow[i + 1] {                 newRow[i] *= 2                 newRow[i + 1] = 0             }         }         return newRow     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/50c\/438\/94f\/50c43894fbf7b0e3ab528c0803461447.png\" width=\"1024\" height=\"155\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/50c\/438\/94f\/50c43894fbf7b0e3ab528c0803461447.png\"\/><\/figure>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/09b\/84b\/83f\/09b84b83f3be01b80cdf47a5911a9c3d.gif\" width=\"538\" height=\"498\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/09b\/84b\/83f\/09b84b83f3be01b80cdf47a5911a9c3d.gif\"\/><\/figure>\n<p>\u041a\u0440\u0443\u0442\u043e!!<br \/>\u0417\u0430 2 \u0448\u0430\u0433\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u0433\u0440\u044b 2048. \u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0438 \u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u043f\u043b\u0438\u0442\u043e\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0431\u0435\u0437 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u043a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043d\u0435\u0442 \u0438\u043d\u0434\u0438\u043a\u0430\u0446\u0438\u0438 \u043e\u0431 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0438 \u0438\u0433\u0440\u044b \u0438 \u0441\u0447\u0435\u0442\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u043f\u043b\u0438\u0442\u043e\u043a \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435.<\/p>\n<h3>UI \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0438\u0433\u0440\u044b 2048<\/h3>\n<h3>\u0428\u0410\u0413 3. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 \u043a \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a<\/h3>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u043a \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u0438 \u043d\u0430\u0434\u0435\u043b\u0438\u043c \u043d\u0430\u0448\u0438 \u043f\u043b\u0438\u0442\u043a\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c value, \u043d\u043e \u0438 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c <code>position<\/code> \u043f\u043b\u0438\u0442\u043a\u0438 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0443 \u043f\u043b\u0438\u0442\u043a\u0443 \u0431\u0443\u0434\u0435\u0442 \u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u00a0<code>struct Tile<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u043b\u0438\u0442\u043a\u0438\u00a0<code>position<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u00a0<code>struct Position { var row: int var col: Int}<\/code>, a \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u0434\u0432\u0443\u0445\u043c\u0435\u0440\u043d\u044b\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u043c\u00a0<code>var board: [[Tile]]<\/code>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/19f\/5dc\/924\/19f5dc9240be62048e99a52c1b7aa389.png\" width=\"1024\" height=\"269\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/19f\/5dc\/924\/19f5dc9240be62048e99a52c1b7aa389.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a2b\/bd9\/60a\/a2bbd960a10cf63b4d1e68649149cae6.png\" width=\"1024\" height=\"383\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a2b\/bd9\/60a\/a2bbd960a10cf63b4d1e68649149cae6.png\"\/><\/figure>\n<pre><code class=\"swift\">import SwiftUI  struct Position {     var row: Int     var col: Int }  struct Tile {     var value: Int     var position: Position }<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 GameViewModel \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Tile:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  enum Direction {     case up, down, left, right }  class GameViewModel: ObservableObject {     @Published var tiles: [[Tile]] = []     @Published var isGameOver = false     init() {         resetGame()     }         func resetGame() {         isGameOver = false         tiles = (0..&lt;4).map { row in                 (0..&lt;4).map { col in                     Tile(value: 0, position: Position(row: row, col: col))                 }             }         addNewTile()         addNewTile()         }      func addNewTile() {         var emptyPositions: [Position] = []         for row in 0..&lt;4 {             for col in 0..&lt;4 {                 if tiles[row][col].value == 0 {                     emptyPositions.append(Position(row: row, col: col))                 }             }         }         if let randomPosition = emptyPositions.randomElement() {             let newValue = Bool.random() ? 2 : 4             tiles[randomPosition.row][randomPosition.col].value = newValue         }     }      func move(_ direction: Direction) {         var moved = false          \/\/ Rotate the board so we can always handle the move as a \"left\" move         switch direction {         case .up:             rotateLeft()         case .down:             rotateRight()         case .right:             rotateRight()             rotateRight()         case .left:             break         }          for i in 0..&lt;4 {             let row = getRow(i)             let compressedRow = compressRow(row)             let mergedRow = mergeRow(compressedRow)             if mergedRow != row {                 moved = true                 updateRow(i, with: mergedRow)             }         }          switch direction {         case .up:             rotateRight()         case .down:             rotateLeft()         case .right:             rotateRight()             rotateRight()         case .left:             break         }          if moved {             addNewTile()             checkGameOver()         }     }      func checkGameOver() {         \/\/ Implement the logic to check if the game is over     }      private func rotateLeft() {         tiles = (0..&lt;4).map { col in             (0..&lt;4).map { row in                 var tile = tiles[row][3 - col]                  tile.position = Position(row: col, col: row)                  return tile             }         }     }      private func rotateRight() {         tiles = (0..&lt;4).map { col in             (0..&lt;4).map { row in                  var tile = tiles[3 - row][col]                  tile.position = Position(row: col, col:  row)                  return tile             }         }     }      private func getRow(_ index: Int) -&gt; [Tile] {         return tiles[index]     }      private func updateRow(_ index: Int, with newRow: [Tile]) {         for col in 0..&lt;4 {             tiles[index][col] = newRow[col]         }     }      private func compressRow(_ row: [Tile]) -&gt; [Tile] {         let nonZeroTiles = row.filter { $0.value != 0 }         \/\/ Guard to check if we need to compress        guard !nonZeroTiles.isEmpty, nonZeroTiles.count != 4,           !(nonZeroTiles.count == 1 &amp;&amp; nonZeroTiles[0].position.col == 0)          else {             \/\/ If the row is already in a compressed state, return it as is             return row         }          \/\/ Create new row with non-zero tiles and update their positions         let newRow: [Tile] = nonZeroTiles.enumerated().map { (index, tile) in             var updatedTile = tile             updatedTile.position =                                 Position(row: tile.position.row, col: index)             return updatedTile         }          \/\/ Add zeros to the end of the row with updated positions         let zeros = (newRow.count..&lt;row.count).map { colIndex in             Tile(value: 0, position:                   Position(row: row[0].position.row, col: colIndex))         }          return newRow + zeros     }      private func mergeRow(_ row: [Tile]) -&gt; [Tile] {         var newRow = row                 let nonZeroTiles = row.filter { $0.value != 0 }                 \/\/ If the row has less than 2 tiles return it as is         guard nonZeroTiles.count &gt; 1 else {             return row         }          for i in 0..&lt;row.count - 1 {             if newRow[i].value != 0 &amp;&amp; newRow[i].value == newRow[i + 1].value {                                  \/\/ Merge tiles                 newRow[i].value *= 2                                  \/\/ New zero tile on i + ! position                 newRow[i + 1] = Tile(value: 0, position:                            Position(row: newRow[i].position.row, col: i + 1))             }         }          \/\/ Compress the row after merging         return compressRow(newRow)     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fb9\/c43\/904\/fb9c4390423da3c9e931f7092c2a16ca.png\" width=\"1024\" height=\"258\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fb9\/c43\/904\/fb9c4390423da3c9e931f7092c2a16ca.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/746\/3c1\/af5\/7463c1af5eb051067ed68350b88d7425.png\" width=\"1024\" height=\"361\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/746\/3c1\/af5\/7463c1af5eb051067ed68350b88d7425.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/82b\/d84\/51c\/82bd8451cc19b7acd69b61beb4a5d4ba.png\" width=\"1024\" height=\"498\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/82b\/d84\/51c\/82bd8451cc19b7acd69b61beb4a5d4ba.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>GameView c TileView<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct GameView: View {     @StateObject private var viewModel = GameViewModel()      var body: some View {         VStack {             Text(\"2048\")                 .font(.largeTitle)                 .padding()                          GridView(tiles: viewModel.tiles)                 .padding()                 .gesture(                     DragGesture()                         .onEnded { value in                             let horizontalAmount = value.translation.width                             let verticalAmount = value.translation.height                                                          if abs(horizontalAmount) &gt; abs(verticalAmount) {                                 if horizontalAmount &gt; 0 {                                     viewModel.move(.right)                                 } else {                                     viewModel.move(.left)                                 }                             } else {                                 if verticalAmount &gt; 0 {                                     viewModel.move(.down)                                 } else {                                     viewModel.move(.up)                                 }                             }                         }                 )                          Button(action: {                 viewModel.resetGame()             }) {                 Text(\"Restart\")                     .font(.title)                     .padding()             }         }     } }  struct GridView: View {     let tiles: [[Tile]]      var body: some View {         VStack(spacing: 8) {             ForEach(0..&lt;4) { row in                 HStack(spacing: 8) {                     ForEach(0..&lt;4) { col in                         TileView(tile: tiles[row][col])                     }                 }             }         }     } }  struct TileView: View {     let tile: Tile      var body: some View {         Text(tile.value == 0 ? \"\" : \"\\(tile.value)\")             .frame(width: 80, height: 80)             .background(Color.gray.opacity(0.4))             .cornerRadius(10)             .font(.title)             .foregroundColor(.black)     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u043e\u0434 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438 \u0432\u00a0<code>GameViewModel\u00a0<\/code>\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0fc\/c0f\/47d\/0fcc0f47d7307b47278009ac917779c3.png\" width=\"1230\" height=\"358\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0fc\/c0f\/47d\/0fcc0f47d7307b47278009ac917779c3.png\"\/><\/figure>\n<p>\u0421\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c ChatGPT, \u043a\u0430\u043a \u0435\u0451 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fd2\/008\/e86\/fd2008e86c39c9767700f84424509202.png\" width=\"1024\" height=\"270\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fd2\/008\/e86\/fd2008e86c39c9767700f84424509202.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8c4\/c26\/e38\/8c4c26e3899b9db5dd17858a5fc44aa8.png\" width=\"1024\" height=\"350\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8c4\/c26\/e38\/8c4c26e3899b9db5dd17858a5fc44aa8.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c0d\/b8f\/92e\/c0db8f92e1cc5be24f28fde9ccec9415.png\" width=\"1024\" height=\"364\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c0d\/b8f\/92e\/c0db8f92e1cc5be24f28fde9ccec9415.png\"\/><\/figure>\n<pre><code class=\"swift\">struct Position:Equatable {     var row: Int     var col: Int }  struct Tile: Equatable {     var value: Int     var position: Position }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4d0\/c86\/0ef\/4d0c860ef97bdd72c559095f6f4b2b37.png\" width=\"1024\" height=\"419\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4d0\/c86\/0ef\/4d0c860ef97bdd72c559095f6f4b2b37.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fe8\/25f\/ee7\/fe825fee70ba2600a951aa1559289805.png\" width=\"1152\" height=\"214\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fe8\/25f\/ee7\/fe825fee70ba2600a951aa1559289805.png\"\/><\/figure>\n<pre><code class=\"swift\">struct Tile: Equatable {     var value: Int     var position: Position      \/\/ Manually implement Equatable conformance    \/* static func == (lhs: Tile, rhs: Tile) -&gt; Bool {         return lhs.value == rhs.value &amp;&amp;                lhs.position == rhs.position     }*\/ }  struct Position: Equatable {     var row: Int     var col: Int }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/086\/12f\/a07\/08612fa07b9f993f4e8df548b7fff3b5.png\" width=\"1024\" height=\"476\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/086\/12f\/a07\/08612fa07b9f993f4e8df548b7fff3b5.png\"\/><\/figure>\n<p>\u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b\u00a0<code>Position<\/code><strong>\u00a0<\/strong>\u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443<strong>\u00a0<\/strong><code>Equatable<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f Swift \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438,<strong>\u00a0<\/strong>\u0438 \u0440\u0443\u0447\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>value<\/code>, \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0433\u0440\u044b 2048 :<\/p>\n<pre><code class=\"swift\">struct Tile: Equatable {     var value: Int     var position: Position      \/\/ Manually implement Equatable conformance     static func == (lhs: Tile, rhs: Tile) -&gt; Bool {         return lhs.value == rhs.value     } }  struct Position: Equatable {     var row: Int     var col: Int }<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u0430\u043a \u0438 \u043f\u0440\u0435\u0436\u0434\u0435, \u043d\u043e \u0441 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 <code>Tile<\/code> \u0441\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c <code>position<\/code>:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1d1\/e00\/bac\/1d1e00bac36d235e82f6a925da6bd5a6.gif\" width=\"634\" height=\"422\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1d1\/e00\/bac\/1d1e00bac36d235e82f6a925da6bd5a6.gif\"\/><\/figure>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043b\u0438\u0442\u043a\u0438<strong> <\/strong><code>TileView<\/code> \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435, \u0438 \u043f\u0435\u0440\u0432\u043e\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, &#8212; \u044d\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 <code>TileView<\/code> \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 <code>.position<\/code>, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e<strong> <\/strong><code>position<\/code> \u0441\u0430\u043c\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 <code>Tile<\/code>.<\/p>\n<h3>\u0428\u0410\u0413 4. \u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 .position\u00a0\u0434\u043b\u044f\u00a0TileView<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/945\/346\/cac\/945346cac6bf65ee5874b61bdac24fa3.png\" width=\"1024\" height=\"203\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/945\/346\/cac\/945346cac6bf65ee5874b61bdac24fa3.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f34\/b19\/a44\/f34b19a44f2d97e9d706044986c8cbdc.png\" width=\"1024\" height=\"361\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f34\/b19\/a44\/f34b19a44f2d97e9d706044986c8cbdc.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8e0\/b7c\/6dc\/8e0b7c6dcf6bd78df0ae987b2cfbf476.png\" width=\"1158\" height=\"646\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8e0\/b7c\/6dc\/8e0b7c6dcf6bd78df0ae987b2cfbf476.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 TileView \u0438 GridView<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  \/\/ Define the TileView struct TileView: View {     let tile: Tile      var body: some View {         Text(tile.value == 0 ? \"\" : \"\\(tile.value)\")             .frame(width: 80, height: 80)             .background( Color.gray.opacity(0.4))             .cornerRadius(10)             .font(.title)             .foregroundColor(.black)             .position(getTilePosition())     }      private func getTilePosition() -&gt; CGPoint {         let tileSize: CGFloat = 80 \/\/ Adjust based on tile size and padding         let spacing: CGFloat = 8 \/\/ Space between tiles          let x =              CGFloat(tile.position.col) * (tileSize + spacing) + tileSize \/ 2         let y =              CGFloat(tile.position.row) * (tileSize + spacing) + tileSize \/ 2          return CGPoint(x: x, y: y)     } }  \/\/ Define the GridView to use TileView struct GridView: View {     let tiles: [[Tile]]      var body: some View {         ZStack {             ForEach(tiles.flatMap { $0 }, id: \\.position) { tile in                 TileView(tile: tile)             }         }         .frame(width: 4 * 80 + 3 * 8, height: 4 * 80 + 3 * 8) \/\/ Adjust frame size     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/26d\/fd7\/9b1\/26dfd79b1ae1133d2ec9d9254005810d.png\" width=\"1024\" height=\"687\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/26d\/fd7\/9b1\/26dfd79b1ae1133d2ec9d9254005810d.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<h3>\u0428\u0410\u0413 6. \u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u00a0Identifiable\u00a0\u0434\u043b\u044f\u00a0ForEach<\/h3>\n<p>\u0420\u0430\u043d\u0435\u0435 \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f\u00a0\u00a0<code>GridView<\/code>:<\/p>\n<pre><code class=\"swift\">struct GridView: View {     let tiles: [[Tile]]     var body: some View {         VStack(spacing: 8) {             ForEach(0..&lt;4) { row in                 HStack(spacing: 8) {                     ForEach(0..&lt;4) { col in                         TileView(value:tiles [row][col])                     }                 }             }         }     } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u0434\u00a0<code>GridView<\/code>:<\/p>\n<pre><code class=\"swift\">\/\/ Define the GridView to use TileView struct GridView: View {     let tiles: [[Tile]]      var body: some View {         ZStack {             ForEach(tiles.flatMap { $0 }, id: \\.position) { tile in                 TileView(tile: tile)             }         }         .frame(width: 4 * 80 + 3 * 8, height: 4 * 80 + 3 * 8) \/\/ Adjust frame size     } }<\/code><\/pre>\n<p>\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438<strong>\u00a0<\/strong>\u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u00a0<code>.position\u00a0<\/code>\u0434\u043b\u044f\u00a0<code>TileView<\/code>, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0441\u0435\u0442\u043a\u0435, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0435\u0439 \u0438\u0437 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0445\u00a0<code>ForEach<\/code>, \u043f\u0440\u043e\u043f\u0430\u043b\u0430. ChatGPT \u0447\u0435\u0442\u043a\u043e \u044d\u0442\u043e \u0443\u043b\u043e\u0432\u0438\u043b \u0438 \u201d\u0432\u044b\u0442\u044f\u043d\u0443\u043b\u201c 2D\u00a0 \u043c\u0430\u0441\u0441\u0438\u0432 \u0432 1D \u043c\u0430\u0441\u0441\u0438\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430\u00a0<code>flatMap<\/code>\u00a0\u0438 \u0434\u043b\u044f \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e\u00a0<code>ForEach<\/code>\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u044d\u0442\u043e\u0442 \u043c\u0430\u0441\u0441\u0438\u0432, \u043f\u043e\u043b\u0430\u0433\u0430\u044f, \u0447\u0442\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u00a0<code>position<\/code>\u043f\u043b\u0438\u0442\u043a\u0438\u00a0<code>Tile<\/code>\u00a0\u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043b\u0438\u0442\u043a\u0438\u00a0<code>TileView<\/code>\u00a0\u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435, \u043d\u043e \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u0441\u0430\u043c\u0443 \u043f\u043b\u0438\u0442\u043a\u0443\u00a0<code>Tile<\/code>. <\/p>\n<p>\u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a, \u0442\u0430\u043a \u043a\u0430\u043a\u00a0 \u043f\u043e\u0437\u0438\u0446\u0438\u044f<strong>\u00a0<\/strong><code>position<\/code><strong>\u00a0<\/strong>\u043f\u043b\u0438\u0442\u043a\u0438\u00a0<code>Tile<\/code>\u00a0\u0441 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0438\u0433\u0440\u044b \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0445\u043e\u0442\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u0439 \u0436\u0435 \u0441\u0430\u043c\u043e\u0439, \u0442\u0430\u043a \u0447\u0442\u043e <code>position<\/code><strong>\u00a0<\/strong>\u0432\u043e\u0432\u0441\u0435 \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0443\u0436\u043d\u044b\u043c \u043d\u0430\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043f\u043b\u0438\u0442\u043a\u0438<strong>\u00a0<\/strong><code>Tile<\/code>.<\/p>\n<pre><code class=\"swift\">\/\/ Define the GridView to use TileView struct GridView: View {     let tiles: [[Tile]]      var body: some View {         ZStack {             ForEach(tiles.flatMap { $0 }) { tile in                 TileView(tile: tile)             }         }         .frame(width: 4 * 80 + 3 * 8, height: 4 * 80 + 3 * 8) \/\/ Adjust frame size     } }<\/code><\/pre>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u0430 \u043a\u0430\u043a\u0430\u044f-\u0442\u043e \u0434\u0440\u0443\u0433\u0430\u044f \u0432\u0435\u0449\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043f\u043b\u0438\u0442\u043a\u0443 \u043d\u0430\u0432\u0441\u0435\u0433\u0434\u0430 \u0438 \u043e\u0434\u043d\u043e\u0437\u043d\u0430\u0447\u043d\u043e. \u041d\u0435\u0432\u0430\u0436\u043d\u043e, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0441 \u044d\u0442\u043e\u0439 \u043f\u043b\u0438\u0442\u043a\u043e\u0439, \u043d\u0435\u0432\u0430\u0436\u043d\u043e \u043a\u0430\u043a \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u043d\u0430 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u043c\u044b \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u044d\u0442\u043e \u0442\u0430 \u0436\u0435 \u0441\u0430\u043c\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430, \u043d\u0430\u0448<code>ForEach<\/code><strong>\u00a0<\/strong>\u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u0447\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u0441 \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0438\u0442\u043a\u043e\u0439 \u043e\u043d \u0438\u043c\u0435\u0435\u0442 \u0434\u0435\u043b\u043e. \u042d\u0442\u043e \u0432\u0430\u0436\u043d\u043e \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041d\u043e \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u0443\u0431\u0435\u0440\u0435\u043c \u00a0<code>id: \\.position,<\/code>\u00a0\u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d25\/647\/ffb\/d25647ffb756cfe214fc70e9cd06761d.png\" width=\"1024\" height=\"448\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d25\/647\/ffb\/d25647ffb756cfe214fc70e9cd06761d.png\"\/><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043f\u0440\u043e\u0441\u0438\u043c ChatGPT, \u0447\u0442\u043e \u043d\u0430\u043c \u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u044d\u0442\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u043e\u0439:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/91a\/dc3\/205\/91adc3205b641b6dc8936c14a32b5d24.png\" width=\"1024\" height=\"151\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/91a\/dc3\/205\/91adc3205b641b6dc8936c14a32b5d24.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/36a\/1e0\/342\/36a1e03424776e5130cff0ac250a1191.png\" width=\"1024\" height=\"147\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/36a\/1e0\/342\/36a1e03424776e5130cff0ac250a1191.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5fd\/2e0\/594\/5fd2e0594fd760e6baedcd134e11f22d.png\" width=\"1024\" height=\"488\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5fd\/2e0\/594\/5fd2e0594fd760e6baedcd134e11f22d.png\"\/><\/figure>\n<pre><code class=\"swift\">struct Tile: Equatable, Identifiable { \/\/ Manually    static func == (lhs: Tile, rhs: Tile) -&gt; Bool {         return lhs.value == rhs.value     }          var value: Int     var position: Position     var id = UUID()  \/\/ This provides a unique identifier for each tile }  struct Position: Equatable {     var row: Int     var col: Int }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3c3\/22b\/5b5\/3c322b5b562455b530290955dc9d88e4.png\" width=\"1024\" height=\"464\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3c3\/22b\/5b5\/3c322b5b562455b530290955dc9d88e4.png\"\/><\/figure>\n<pre><code class=\"swift\">\/\/ Define the GridView to use TileView struct GridView: View {     let tiles: [[Tile]]      var body: some View {         ZStack {             ForEach(tiles.flatMap { $0 }) { tile in                 TileView(tile: tile)             }         }         .frame(width: 4 * 80 + 3 * 8, height: 4 * 80 + 3 * 8) \/\/ Adjust frame size     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b4c\/f32\/f80\/b4cf32f80a26c622ead6f52145287391.png\" width=\"1024\" height=\"385\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b4c\/f32\/f80\/b4cf32f80a26c622ead6f52145287391.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fd1\/5fe\/bac\/fd15febac03f7afb77cc6a6b6b1ea5d7.gif\" width=\"592\" height=\"454\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fd1\/5fe\/bac\/fd15febac03f7afb77cc6a6b6b1ea5d7.gif\"\/><\/figure>\n<h2>\u0428\u0430\u0433 5. \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f<\/h2>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2e3\/3f5\/4d7\/2e33f54d750184f1e32806c066ea829f.png\" width=\"1024\" height=\"201\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2e3\/3f5\/4d7\/2e33f54d750184f1e32806c066ea829f.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/27f\/a59\/24f\/27fa5924f38dabe87660138ecae9f12b.png\" width=\"1024\" height=\"186\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/27f\/a59\/24f\/27fa5924f38dabe87660138ecae9f12b.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/10a\/6a5\/8c3\/10a6a58c3f334af7be259820b17bf4c9.png\" width=\"1024\" height=\"171\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/10a\/6a5\/8c3\/10a6a58c3f334af7be259820b17bf4c9.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>TileView \u0441 \u043d\u0435\u044f\u0432\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 .transition<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  struct TileView: View {     let tile: Tile     let tileSize: CGFloat     let padding: CGFloat      var body: some View {         RoundedRectangle(cornerRadius: padding)             .fill(Color.colorForTile(tile.value))             .frame(width: tileSize, height: tileSize)             .overlay(                 Text(tile.value &gt; 0 ? \"\\(tile.value)\" : \"\")                     .font(.largeTitle)                     .foregroundColor(.black)             )             .position (getTilePosition())             .animation(.easeInOut(duration: 0.2), value: tile.position)             .transition(.scale)     }      private func getTilePosition() -&gt; CGPoint {       let x = CGFloat(tile.position.col) * (tileSize + padding) + tileSize \/ 2       let y = CGFloat(tile.position.row) * (tileSize + padding) + tileSize \/ 2         return CGPoint(x: x, y: y)     } }  extension Color {    static func colorForTile(_ value: Int) -&gt; Color {         switch value {         case 0: return Color(UIColor.systemGray5)         case 2: return Color(UIColor.systemGray4)         case 4: return Color.orange         case 8: return Color.red         case 16: return Color.purple         case 32: return Color.blue         case 64: return Color.green         case 128: return Color.yellow         case 256: return Color.pink         case 512: return Color.brown         case 1024: return Color.cyan         case 2048: return Color.indigo         default: return Color.mint         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/25a\/eff\/b92\/25aeffb9261e5b9f264007927b365794.png\" width=\"1024\" height=\"269\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/25a\/eff\/b92\/25aeffb9261e5b9f264007927b365794.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>GameView c \u044f\u0432\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 withAnimation<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct GameView: View {     @StateObject private var viewModel = GameViewModel()     let tileSize: CGFloat = 80     let padding: CGFloat = 8     var body: some View {         VStack {             Text(\"2048\")                 .font(.largeTitle)                 .padding()                          GridView(tiles: viewModel.tiles, tileSize: tileSize,                                               padding: padding)                 .gesture(                     DragGesture()                         .onEnded { value in                             withAnimation(.easeInOut) {                                 handleSwipe(value: value)                             }                          }                 )                          Button(action: {               withAnimation(.easeInOut) {                   viewModel.resetGame()                 }             }) {                 Text(\"Restart\")                     .font(.title2)                     .padding()             }         }     }          \/\/ Handle swipe gesture and trigger game actions     private func handleSwipe(value: DragGesture.Value) {         let threshold: CGFloat = 20         let horizontalShift = value.translation.width         let verticalShift = value.translation.height                  if abs(horizontalShift) &gt; abs(verticalShift) {             if horizontalShift &gt; threshold {                 viewModel.move(.right)             } else if horizontalShift &lt; -threshold {                 viewModel.move(.left)             }         } else {             if verticalShift &gt; threshold {                 viewModel.move(.down)             } else if verticalShift &lt; -threshold {                 viewModel.move(.up)             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/69c\/ac0\/60e\/69cac060ea1ae84b9244a52af8672c47.png\" width=\"1024\" height=\"419\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/69c\/ac0\/60e\/69cac060ea1ae84b9244a52af8672c47.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">\/\/ Define the GridView to use TileView struct GridView: View {     let tiles: [[Tile]]     let tileSize : CGFloat     let padding : CGFloat          var body: some View {        ZStack {            \/\/ Background grid             VStack(spacing: padding) {                ForEach(0..&lt;4) { row in                    HStack(spacing: padding) {                        ForEach(0..&lt;4) { col in                            RoundedRectangle(cornerRadius:padding)                                .fill(Color.colorForTile(0))                                .frame(width: tileSize, height: tileSize)                        }                    }                }            }              \/\/ Foreground tiles (only non-zero values)              ForEach(tiles.flatMap { $0 }.filter { $0.value != 0 }){ tile in                 TileView(tile: tile, tileSize: tileSize, padding: padding)              }         }         .frame(width: 4 * tileSize + 3 * padding,                 height: 4 * tileSize +  3 * padding) \/\/ Adjust frame size     }  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/096\/210\/770\/096210770e4a716690d4d628b7efb5fc.png\" width=\"1024\" height=\"590\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/096\/210\/770\/096210770e4a716690d4d628b7efb5fc.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/770\/133\/dae\/770133daeffeb2bc216e538779d644cb.png\" width=\"1024\" height=\"560\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/770\/133\/dae\/770133daeffeb2bc216e538779d644cb.png\"\/><\/figure>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e86\/4e8\/8f7\/e864e88f78ffb6ea0e27621af89f5dd5.gif\" width=\"402\" height=\"666\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e86\/4e8\/8f7\/e864e88f78ffb6ea0e27621af89f5dd5.gif\"\/><\/figure>\n<p>A \u0432\u043e\u0442 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u00a0 \u201c\u041c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0439 \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u0438\u201d (Slow Animation) :<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fc3\/de1\/399\/fc3de1399a6366f5506d2f209ff95f45.gif\" width=\"368\" height=\"730\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fc3\/de1\/399\/fc3de1399a6366f5506d2f209ff95f45.gif\"\/><\/figure>\n<p>\u041c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u043f\u043b\u0438\u0442\u043e\u043a \u0430\u043d\u0438\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0438\u0437 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u044b (.center), \u0438 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0445\u043e\u0440\u043e\u0448\u043e, \u043d\u0430\u043c \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u043f\u043b\u0438\u0442\u043e\u043a\u00a0 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u201c\u043f\u043e \u043c\u0435\u0441\u0442\u0443\u201d \u043f\u043b\u0438\u0442\u043e\u043a \u0432 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435.<\/p>\n<h4>\u0423\u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 .transition (.scale)<\/h4>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043f\u0440\u043e\u0441\u0438\u043c, \u043a\u0430\u043a \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u043e\u0433\u043e \u0443 ChatGPT:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2fd\/fc9\/635\/2fdfc96356d046831d176566f281acec.png\" width=\"1024\" height=\"379\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2fd\/fc9\/635\/2fdfc96356d046831d176566f281acec.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fe2\/466\/d97\/fe2466d978c41bb5f7eece696e1db6cc.png\" width=\"1024\" height=\"753\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fe2\/466\/d97\/fe2466d978c41bb5f7eece696e1db6cc.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ed0\/2dd\/c96\/ed02ddc96decffaf8214e6a807fb2594.png\" width=\"1024\" height=\"204\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ed0\/2dd\/c96\/ed02ddc96decffaf8214e6a807fb2594.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 TileView c .transition (.scale) \u0438 .transition(.offset):<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct TileView: View {     let tile: Tile     let tileSize: CGFloat     let padding: CGFloat         var body: some View {        let tilePosition = getTilePosition()                 RoundedRectangle(cornerRadius:padding)             .fill(Color.colorForTile(tile.value))             .frame(width: tileSize, height: tileSize)             .overlay(                 Text(tile.value &gt; 0 ? \"\\(tile.value)\" : \"\")                     .font(.largeTitle)                     .foregroundColor(.black)             )             .position(tilePosition)             .animation(.easeInOut(duration: 0.2), value: tile.position)               .transition(.scale(scale: 0.12).combined (with: .offset(                              x: tilePosition.x - 2.0 * tileSize,                              y: tilePosition.y - 2.0 * tileSize)))     }          private func getTilePosition() -&gt; CGPoint {       let x = CGFloat(tile.position.col) * (tileSize + padding) + tileSize \/ 2       let y = CGFloat(tile.position.row) * (tileSize + padding) + tileSize \/ 2                  return CGPoint(x: x, y: y)     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0bf\/6cc\/3b3\/0bf6cc3b387e55628d947d0eceb9f264.png\" width=\"1024\" height=\"462\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0bf\/6cc\/3b3\/0bf6cc3b387e55628d947d0eceb9f264.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d8e\/c45\/5fd\/d8ec455fd08d51462c08880ddd4abf7b.png\" width=\"1024\" height=\"587\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d8e\/c45\/5fd\/d8ec455fd08d51462c08880ddd4abf7b.png\"\/><\/figure>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/539\/e05\/f3e\/539e05f3e9e740e5d9e4679a033f48f4.gif\" width=\"364\" height=\"736\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/539\/e05\/f3e\/539e05f3e9e740e5d9e4679a033f48f4.gif\"\/><\/figure>\n<p>A \u0432\u043e\u0442 \u0432 \u0440\u0435\u0436\u0438\u043c\u0435 \u00a0 \u201c\u041c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0439 \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u0438\u201d (Slow Animation) :<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5cc\/ad4\/da0\/5ccad4da0e122112c4636b07ba5c996b.gif\" width=\"364\" height=\"736\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5cc\/ad4\/da0\/5ccad4da0e122112c4636b07ba5c996b.gif\"\/><\/figure>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0437\u0434\u0435\u0441\u044c, \u0441 \u043d\u0438\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u043e\u0441\u0442\u0435 :<\/p>\n<h3>\u0428\u0410\u0413 6.\u00a0 \u0426\u0432\u0435\u0442\u0430 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/63c\/bde\/1e3\/63cbde1e3d0dc3e9eda6e0a4933b53b8.png\" width=\"1024\" height=\"200\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/63c\/bde\/1e3\/63cbde1e3d0dc3e9eda6e0a4933b53b8.png\"\/><\/figure>\n<h3>\u0428\u0430\u0433 7.\u00a0 \u0421\u0447\u0435\u0442 score \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a23\/a44\/19f\/a23a4419ff2ba869743ea8f06f240641.png\" width=\"1024\" height=\"204\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a23\/a44\/19f\/a23a4419ff2ba869743ea8f06f240641.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 8.\u00a0 \u041e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u0435 \u0438\u0433\u0440\u044b 2048.\u00a0<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b9b\/46b\/7a4\/b9b46b7a474aaf3d7a436febb95db2f7.png\" width=\"1024\" height=\"98\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b9b\/46b\/7a4\/b9b46b7a474aaf3d7a436febb95db2f7.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/99e\/2b9\/6ae\/99e2b96aecbe4a54e77df52a33d7ff52.png\" width=\"1024\" height=\"149\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/99e\/2b9\/6ae\/99e2b96aecbe4a54e77df52a33d7ff52.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 9.\u00a0 \u041e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0436\u0435\u0441\u0442\u0430 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048.<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2d3\/098\/05f\/2d309805f6918b39c05a88d6416cccf1.png\" width=\"1024\" height=\"417\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2d3\/098\/05f\/2d309805f6918b39c05a88d6416cccf1.png\"\/><\/figure>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u044b\u0448\u0435\u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/944\/668\/610\/94466861071880e2d15a3f8103b2a0da.gif\" width=\"368\" height=\"730\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/944\/668\/610\/94466861071880e2d15a3f8103b2a0da.gif\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0438\u0433\u0440\u044b 2048 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0\u00a0<code>bestMoveDirection()<\/code>, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0443\u0447\u043d\u043e\u0439\u00a0<strong>swipe<\/strong>\u00a0\u0436\u0435\u0441\u0442 \u043d\u0430 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043f\u043b\u0438\u0442\u043e\u043a \u0432 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438. \u0438 \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430\u00a0&#171;\u0436\u0430\u0434\u043d\u044b\u0439&#187; (greedy)  \u0418\u0418 (<strong>AI)<\/strong>\u00a0\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0432 \u0438\u0433\u0440\u0435 2048.\u00a0<\/p>\n<h2>\u0418\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442 (AI) \u0432 \u0438\u0433\u0440\u0435 2048<\/h2>\n<h3>\u0428\u0410\u0413 10.\u00a0 \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 AI \u0432 \u0438\u0433\u0440\u0443 2048<\/h3>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0418\u0418 \u0432 \u0438\u0433\u0440\u0443 2048 \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u043e\u0436\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0438\u0439 \u0445\u043e\u0434 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0448\u0430\u0433\u0435. \u0418\u0418 \u0431\u0443\u0434\u0435\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u00a0<code>\u0444\u0443\u043d\u043a\u0446\u0438\u044e bestMoveDirection()<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0440\u0430\u043d\u0435\u0435 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438, \u0447\u0442\u043e\u0431\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0445\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c, \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044f\u0441\u044c, \u043d\u0430 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u043c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0438 \u0441\u0447\u0435\u0442\u0430. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0418\u0418 \u043c\u043e\u0436\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0433\u0440\u0430\u0442\u044c \u0432 \u0438\u0433\u0440\u0443 2048, \u0434\u0435\u043b\u0430\u044f \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0445\u043e\u0434\u044b.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0445\u043e\u0434\u0430 \u0418\u0418, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0435\u0433\u043e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u043d\u043e\u0441\u0442\u044c\u044e, \u0438, \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0440\u0443\u0447\u043d\u044b\u043c\u00a0 \u0440\u0435\u0436\u0438\u043c\u043e\u043c \u0441\u043e swipe \u0436\u0435\u0441\u0442\u043e\u043c \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0418\u0418.<\/p>\n<p>\u041d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0439\u043c\u0435\u043c, \u043a\u0430\u043a\u0438\u0435 \u0432 SwiftUI \u0435\u0441\u0442\u044c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 \u0440\u0430\u0432\u043d\u044b\u0435 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e2c\/d9a\/4f7\/e2cd9a4f78c043aeffcfceeb13b8149d.png\" width=\"1024\" height=\"189\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e2c\/d9a\/4f7\/e2cd9a4f78c043aeffcfceeb13b8149d.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/008\/988\/18c\/00898818c3d6f55cc85e51ad61d03a2a.png\" width=\"1024\" height=\"270\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/008\/988\/18c\/00898818c3d6f55cc85e51ad61d03a2a.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>View, \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0449\u0435\u0435 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043a\u0430\u0436\u0434\u0443\u044e \u0441\u0435\u043a\u0443\u043d\u0434\u0443<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  struct PeriodicTaskView: View {     @State private var counter = 0          \/\/ Create a timer publisher that fires every second     let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()      var body: some View {         VStack {             Text(\"Counter: \\(counter)\")                 .font(.largeTitle)                 .padding()              \/\/ Example of something happening periodically             Text(\"This text will update every second.\")         }         .onReceive(timer) { _ in             \/\/ Increment the counter every time the timer fires             counter += 1                          \/\/ Place any other periodic code here             print(\"Timer fired. Counter is now \\(counter).\")         }     } }   #Preview {             PeriodicTaskView()  }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fbf\/a26\/d3f\/fbfa26d3f73599c086b0ec8702b4d540.png\" width=\"1024\" height=\"789\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fbf\/a26\/d3f\/fbfa26d3f73599c086b0ec8702b4d540.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5d1\/50b\/42b\/5d150b42b710a0877a3bc201fd756a67.png\" width=\"1024\" height=\"312\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d1\/50b\/42b\/5d150b42b710a0877a3bc201fd756a67.png\"\/><\/figure>\n<pre><code class=\"swift\">struct GameView: View {     @ObservedObject var viewModel: GameViewModel     @State private var isAIEnabled = false          \/\/ Create a timer publisher that fires every second     let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()      var body: some View {         VStack {             Toggle(\"Enable AI\", isOn: $isAIEnabled)                 .padding()              \/\/ Your game UI components go here...          }         .onReceive(timer) { _ in             if isAIEnabled {                 let direction = viewModel.bestMoveDirection()                 viewModel.move(direction)             }         }     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2bf\/7e9\/914\/2bf7e9914e1db74e7b2efbed889ed451.png\" width=\"1024\" height=\"272\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2bf\/7e9\/914\/2bf7e9914e1db74e7b2efbed889ed451.png\"\/><\/figure>\n<h3>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 .onReceive (timer) \u0438 Timer.publish \u0432 GameView\u00a0<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/63b\/bc7\/4c1\/63bbc74c127649c8ef6f6565e7c78503.png\" width=\"1024\" height=\"224\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/63b\/bc7\/4c1\/63bbc74c127649c8ef6f6565e7c78503.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/763\/378\/fef\/763378fef47cd50aaf7ea67664babd06.png\" width=\"1024\" height=\"326\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/763\/378\/fef\/763378fef47cd50aaf7ea67664babd06.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ac1\/a49\/4bf\/ac1a494bfc415d86cd4988100f0755e0.png\" width=\"1024\" height=\"161\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ac1\/a49\/4bf\/ac1a494bfc415d86cd4988100f0755e0.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameView c Timer.publish \u0438 .omReceive<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  struct GameView: View {     @ObservedObject var viewModel = GameViewModel ()      let tileSize: CGFloat = 80     let padding: CGFloat = 8          @State var isAIPlaying = false     @State private var isShowingOptimalDirection = false          \/\/ Timer that triggers every 0.5 seconds     private let timer =                 Timer.publish(every: 0.5, on: .main, in:.common).autoconnect()          var body: some View {         VStack {             \/\/ Your game UI components here (e.g., grid view, score display)...              HStack {                 Button(action: {                     isAIPlaying.toggle()                 }) {                     HStack {                         Image(systemName:                                   isAIPlaying ? \"checkmark.square\" : \"square\")                             .resizable()                             .frame(width: 24, height: 24)                                                                            Text( isAIPlaying ? \"AI Stop\" : \"AI Play\")                      }                 }                 .padding()                 .background(.accentColor)             }                          if viewModel.isGameOver {                 Text(viewModel.isGameOver  ? \"Game Over\": \" ___ \")                     .font(.title)                     .foregroundColor(viewModel.isGameOver  ? .red : .clear)             }         }         .padding()          \/\/ This triggers AI moves at intervals when AI is playing         .onReceive(timer) { _ in             if isAIPlaying {                 viewModel.executeAIMove()             }         }     } }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/95b\/0f3\/3fd\/95b0f33fd4d45fab3500d7e6235d9b04.png\" width=\"1024\" height=\"716\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/95b\/0f3\/3fd\/95b0f33fd4d45fab3500d7e6235d9b04.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/43b\/a7d\/1c9\/43ba7d1c998777008b2f2566153c2a94.png\" width=\"1024\" height=\"278\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/43b\/a7d\/1c9\/43ba7d1c998777008b2f2566153c2a94.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c39\/ced\/ed2\/c39ceded2a601cc0a1944b12074b85f3.png\" width=\"1024\" height=\"142\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c39\/ced\/ed2\/c39ceded2a601cc0a1944b12074b85f3.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">class GameViewModel: ObservableObject {     @Published var tiles: [[Tile]] = []     @Published var score: Int = 0              private var aiGame = AIGame()          init() {         resetGame()     }          func resetGame() { . . .}         \/\/ Reset the game board, score, and other states                func executeAIMove() {         var  bestDirection : Direction          guard !isGameOver else { return }                 bestDirection = bestMoveDirection()         move(bestDirection)         }                 func bestMoveDirection() -&gt; Direction {         var bestDirection: Direction = .right         var maxScore = 0                  for direction in Direction.allCases {             let result =                        aiGame.oneStepGame(direction: direction, matrix: tiles)             if result.moved &amp;&amp; result.score &gt;= maxScore {                 maxScore = result.score                 bestDirection = direction             }         }                  return bestDirection     }          func move(_ direction: Direction) {         \/\/ Logic to slide and merge tiles, add newTile if moved and gain the score         let (moved, score) = slide(direction)                  if moved {             self.score += score             addNewTile()         }         checkGameOver()     }      private func checkGameOver() {         if !canMove() {             isGameOver = true         }     }          private func canMove() -&gt; Bool {         return Direction.allCases.contains { direction in             aiGame.oneStepGame(direction: direction, matrix: tiles).moved         }     }          private func addNewTile() {         \/\/ Logic to add a new tile at a random empty position     }          func slide(_ direction: Direction) -&gt; (moved: Bool, score: Int) {         \/\/ Logic to slide and merge tiles, returning whether any tiles moved and the score gained         var moved = false         var totalScore = 0                  \/\/ Rotate board, compress, merge, and update rows...                  return (moved, totalScore)     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/afd\/9e9\/3fe\/afd9e93fe6507a3200976b6b8e922a3c.png\" width=\"1024\" height=\"637\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/afd\/9e9\/3fe\/afd9e93fe6507a3200976b6b8e922a3c.png\"\/><\/figure>\n<p>A \u0432\u043e\u0442 \u043d\u0430\u0448 UI:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6f3\/22c\/92a\/6f322c92a4eb4a8a845cef9e69140bb8.gif\" width=\"364\" height=\"738\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6f3\/22c\/92a\/6f322c92a4eb4a8a845cef9e69140bb8.gif\"\/><\/figure>\n<h3>\u0428\u0410\u0413 11. \u041b\u0443\u0447\u0448\u0430\u044f \u0418\u0418 (AI) \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/55c\/020\/dfe\/55c020dfe946dcb9a0c349ce54a58515.png\" width=\"1024\" height=\"205\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/55c\/020\/dfe\/55c020dfe946dcb9a0c349ce54a58515.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/116\/8a0\/259\/1168a0259526b23f2be3b04f6ff796f3.png\" width=\"1024\" height=\"184\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/116\/8a0\/259\/1168a0259526b23f2be3b04f6ff796f3.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/113\/da4\/aff\/113da4aff09c5db95e82bc205e448dfa.png\" width=\"1024\" height=\"390\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/113\/da4\/aff\/113da4aff09c5db95e82bc205e448dfa.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fe6\/e46\/2e5\/fe6e462e51e77c0bf9294793cd5254fa.png\" width=\"1024\" height=\"468\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fe6\/e46\/2e5\/fe6e462e51e77c0bf9294793cd5254fa.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4cc\/ebf\/6ca\/4ccebf6ca3d9d8eb1cdde0217a7344e9.png\" width=\"1024\" height=\"515\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4cc\/ebf\/6ca\/4ccebf6ca3d9d8eb1cdde0217a7344e9.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/025\/61f\/2e3\/02561f2e3e1a6758e1c659a63005b2ce.png\" width=\"1024\" height=\"443\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/025\/61f\/2e3\/02561f2e3e1a6758e1c659a63005b2ce.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 12. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Expectimax<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/de2\/520\/3e3\/de25203e33a95a551e7e732ef509da6c.png\" width=\"1024\" height=\"194\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/de2\/520\/3e3\/de25203e33a95a551e7e732ef509da6c.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bec\/ef3\/3a9\/becef33a9d930c0981eabc0cdc8182c8.png\" width=\"1024\" height=\"511\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bec\/ef3\/3a9\/becef33a9d930c0981eabc0cdc8182c8.png\"\/><\/figure>\n<pre><code class=\"swift\">enum Direction: CaseIterable {     case up, down, left, right }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4d4\/03a\/7d6\/4d403a7d6c647126d341f305faa0e358.png\" width=\"1024\" height=\"163\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4d4\/03a\/7d6\/4d403a7d6c647126d341f305faa0e358.png\"\/><\/figure>\n<pre><code class=\"swift\">struct Tile : Equatable, Identifiable {     var value: Int     var position: Position     var id = UUID()  \/\/ This provides a unique identifier for each tile          \/\/ Manually implement Equatable conformance     static func == (lhs: Tile, rhs: Tile) -&gt; Bool {         return lhs.value == rhs.value     } }  struct Position: Equatable {     var row: Int     var col: Int }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a15\/035\/da4\/a15035da47d3f233fb76611542f79508.png\" width=\"1024\" height=\"557\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a15\/035\/da4\/a15035da47d3f233fb76611542f79508.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0432  expectimax:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func expectimax(board: [[Tile]], depth: Int, isAITurn: Bool) -&gt; Double {       \/\/ Base case: return the board evaluation if depth is 0 or game is over         if depth == 0 || isGameOver(board) {             return evaluateBoard  (board)         }                  \/\/ AI's move (maximize the score)         if isAITurn {             var maxScore = -Double.infinity             for direction in Direction.allCases {                 let newBoard = GameViewModel (matrix: board)                 let (moved, _) = newBoard.slide(direction)                 if moved {                  \/\/ Recur for the next move, but now it's the tile placement's turn                     maxScore = max(maxScore,          expectimax(board: newBoard.tiles, depth: depth - 1, isAITurn: false))                 }             }             return maxScore         }         \/\/ Random tile placement's move (chance node)         else {             var expectedScore = 0.0             let emptyTiles = board.flatMap{$0}.filter{$0.value == 0}             \/\/ If no empty tiles, the game is over             if emptyTiles.isEmpty {                 return evaluateBoard (board)             }                          \/\/ For each empty tile, calculate the expected value             for tile in emptyTiles {                 var boardWith2 = board                 boardWith2[tile.position.row][tile.position.col].value = 2                 var boardWith4 = board                 boardWith4[tile.position.row][tile.position.col].value = 4                                  \/\/ 90% probability of placing a '2' tile, 10% of placing a '4' tile                 expectedScore +=          0.9 * expectimax(board: boardWith2, depth: depth - 1, isAITurn: true)                 expectedScore +=          0.1 * expectimax(board: boardWith4, depth: depth - 1, isAITurn: true)             }             return expectedScore \/ Double(emptyTiles.count)         }     }    func evaluateBoard(_ board: [[Tile]]) -&gt; Double {         let monotonicityWeight = 1.0         let smoothnessWeight = 0.1         let emptyTilesWeight = 2.7         let maxTileWeight = 1.0          let emptyTilesCount =                 Double(board.flatMap{$0}.filter{$0.value == 0}.count)                        return monotonicity(board) * monotonicityWeight +                smoothness(board) * smoothnessWeight +                emptyTilesCount * emptyTilesWeight +                maxTileInCorne() * maxTileWeight     }          func  monotonicity (_ board: [[Tile]]) -&gt; Double {         \/\/ calculate         return 0.0     }     func  smoothness (_ board: [[Tile]]) -&gt; Double {         \/\/ calculate         return 0.0     }      func maxTileInCorner(_ board: [[Tile]]) -&gt; Double          \/\/ calculate         return 0.0     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9d9\/e7c\/2f8\/9d9e7c2f8b3ad9b15d99aec9a41913cf.png\" width=\"1024\" height=\"382\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9d9\/e7c\/2f8\/9d9e7c2f8b3ad9b15d99aec9a41913cf.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/71c\/61f\/942\/71c61f9429c57623defd3038f55543f6.png\" width=\"1024\" height=\"561\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/71c\/61f\/942\/71c61f9429c57623defd3038f55543f6.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8f3\/d10\/dbd\/8f3d10dbdc560f5a17d48dc3688ff7ac.png\" width=\"1024\" height=\"553\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8f3\/d10\/dbd\/8f3d10dbdc560f5a17d48dc3688ff7ac.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/890\/d15\/eb5\/890d15eb5324e80c75d771f4884e9ef6.png\" width=\"1024\" height=\"363\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/890\/d15\/eb5\/890d15eb5324e80c75d771f4884e9ef6.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fc1\/597\/2e5\/fc15972e558226300789a17445d118c5.png\" width=\"1024\" height=\"694\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fc1\/597\/2e5\/fc15972e558226300789a17445d118c5.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 expectimaxBestMove (<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">\/\/ MARK: - Expectimax     func expectimaxBestMove (depth: Int, matr [[Tile]]) -&gt; Direction {         var bestDirection = Direction.right         var bestScore: Double = -Double.infinity          \/\/ for move in possibleMoves {         for direction in Direction.allCases {             var model = GameViewModel (matrix: matrix) \/\/ Initialize Game             let (moved, _ ) = model.slide(direction)             if moved {                let newScore =            expectimaxScore (board: model.tiles, depth: depth, isAITurn: false)                if newScore &gt; bestScore {                     bestScore = newScore                     bestDirection = direction                 }             }         }         return bestDirection     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/df2\/1ee\/abc\/df21eeabc541754e0f800242c539d3c7.png\" width=\"1024\" height=\"286\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/df2\/1ee\/abc\/df21eeabc541754e0f800242c539d3c7.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameViewModel<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">class GameViewModel: ObservableObject {     @Published var tiles: [[Tile]] = []     @Published var isGameOver = false     @Published var score: Int = 0              private var aiGame = AIGame()          init() {         resetGame()     }          func resetGame() { . . .}         \/\/ Reset the game board, score, and other states               \/\/ ------ AI ---------     func executeAIMove() {             guard !isGameOver else { return }             move(bestAIMoveDirection())     }       func bestAIMoveDirection() -&gt; Direction {            aiGame.expectimaxBestMove(depth: 4, matrix: tiles)       }                     \/\/ Other functions: move, slide, compress, merge, and update rows... }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/780\/6ad\/5ed\/7806ad5edd14bb19429c689549e6cd49.png\" width=\"1024\" height=\"371\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/780\/6ad\/5ed\/7806ad5edd14bb19429c689549e6cd49.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>GameView<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  struct GameView: View {     @ObservedObject var viewModel = GameViewModel ()      let tileSize: CGFloat = 80     let padding: CGFloat = 8          @State var isAIPlaying = false     @State private var isShowingOptimalDirection = false          \/\/ Timer that triggers every 0.5 seconds     private let timer =              Timer.publish(every: 0.5, on: .main, in:.common).autoconnect()          var body: some View {         VStack {             \/\/ Your game UI components here (score display)...              HStack {                 Button(action: {                     isAIPlaying.toggle()                 }) {                     HStack {                      Image(systemName:                                   isAIPlaying ? \"checkmark.square\" : \"square\")                             .resizable()                             .frame(width: 24, height: 24)                                                                           Text(isAIPlaying ? \"AI Stop\" : \"AI Play\")                      }                 }                 .padding()             }                          if viewModel.isGameOver {                 Text(viewModel.isGameOver  ? \"Game Over\": \" ___ \")                     .font(.title)                     .foregroundColor(viewModel.isGameOver  ? .red : .clear)             }        \/\/ Your game UI components here (e.g., grid view, reset display)...         }         .padding()          \/\/ This triggers AI moves at intervals when AI is playing         .onReceive(timer) { _ in             if isAIPlaying {                 viewModel.executeAIMove()             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u00a0<code>expectimax<\/code>\u00a0\u043f\u043e\u0438\u0441\u043a \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u043e\u0434\u0430:<\/p>\n<div class=\"floating-image\">\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7d5\/5d3\/dd1\/7d55d3dd16f4ce3efe83e03f3bb31844.gif\" width=\"364\" height=\"738\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7d5\/5d3\/dd1\/7d55d3dd16f4ce3efe83e03f3bb31844.gif\"\/><\/figure>\n<\/div>\n<div class=\"floating-image\">\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cfb\/b24\/5f2\/cfbb245f2c00363e579eeaf849def158.gif\" width=\"364\" height=\"738\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cfb\/b24\/5f2\/cfbb245f2c00363e579eeaf849def158.gif\"\/><\/figure>\n<\/p>\n<\/div>\n<h3>\u0428\u0410\u0413 13. \u0423\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 evaluate()<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cb4\/c24\/fbd\/cb4c24fbd89366fe3de1f443c8857d8c.png\" width=\"1024\" height=\"178\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cb4\/c24\/fbd\/cb4c24fbd89366fe3de1f443c8857d8c.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e86\/bd4\/1da\/e86bd41da9bdc7ee5d8f2bf25f0b2d74.png\" width=\"1024\" height=\"777\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e86\/bd4\/1da\/e86bd41da9bdc7ee5d8f2bf25f0b2d74.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f monotonicity (grid: ) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func monotonicity (_ grid: [[Int]]) -&gt; Double {         func calculateMonotonicity(values: [Int]) -&gt; (Double, Double) {             var increasing = 0.0             var decreasing = 0.0             var current = 0             \/\/ Skip over any initial zeros in the row\/column             while current &lt; values.count &amp;&amp; values[current] == 0 {                 current += 1             }             var next = current + 1             while next &lt; values.count {                 \/\/ Skip over any zeros in the middle                 while next &lt; values.count &amp;&amp; values[next] == 0 {                     next += 1                 }                 if next &lt; values.count {                     let currentValue = values[current] != 0 ?                                               log2(Double(values[current])) : 0                     let nextValue = values[next] != 0 ?                                            log2(Double(values[next])) : 0                     if currentValue &gt; nextValue {                         decreasing += nextValue - currentValue                     } else if currentValue &lt; nextValue {                         increasing += currentValue - nextValue                     }                     \/\/ Move to the next non-zero tile                     current = next                     next += 1                 }             }             return (increasing, decreasing)         }         var rowMonotonicity = (increasing: 0.0, decreasing: 0.0)         var colMonotonicity = (increasing: 0.0, decreasing: 0.0)         \/\/ Check row monotonicity (left-right)         for row in grid {             let (increasing, decreasing) = calculateMonotonicity(values: row)             rowMonotonicity.increasing += increasing             rowMonotonicity.decreasing += decreasing          }         \/\/ Check column monotonicity (up-down)         for col in 0..&lt;grid[0].count {             let columnValues = grid.map { $0[col] }             let (increasing, decreasing) =                                    calculateMonotonicity(values: columnValues)             colMonotonicity.increasing += increasing             colMonotonicity.decreasing += decreasing         }         return max(rowMonotonicity.increasing, rowMonotonicity.decreasing) +                max(colMonotonicity.increasing, colMonotonicity.decreasing)     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c13\/32c\/6d2\/c1332c6d2aaeaa8b3dd5e15834bb7287.png\" width=\"1024\" height=\"324\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c13\/32c\/6d2\/c1332c6d2aaeaa8b3dd5e15834bb7287.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f smoothness (grid: ) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func smoothness(_ grid: [[Int]]) -&gt; Double {       var smoothness: Double = 0       for row in 0..&lt;4 {           for col in 0..&lt;4 {               if grid[row][col] != 0 {                  let value = Double(grid[row][col])                  if col &lt; 3 &amp;&amp; grid[row][col+1] != 0 {                      smoothness -= abs(value - Double(grid[row][col+1]))                  }                  if row &lt; 3 &amp;&amp; grid[row+1][col] != 0 {                       smoothness -= abs(value - Double(grid[row+1][col]))                  }               }           }       }        return smoothness   }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6ef\/3f5\/13a\/6ef3f513a601afa620e842e296803eb9.png\" width=\"1024\" height=\"291\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6ef\/3f5\/13a\/6ef3f513a601afa620e842e296803eb9.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f func emptyTileCount(board: )<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func emptyTileCount(_ board: [[Tile]]) -&gt; Double {     return Double(board.flatMap { $0 }.filter { $0.value == 0 }.count) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/13d\/3b1\/32b\/13d3b132bb0d47930786f36235c29a81.png\" width=\"1024\" height=\"277\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/13d\/3b1\/32b\/13d3b132bb0d47930786f36235c29a81.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f maxTileInCorner(board: ) -&gt; Double <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func maxTileInCorner(_ board: [[Tile]]) -&gt; Double {     let maxTile = board.flatMap { $0 }.max(by: { $0.value &lt; $1.value })?.value ?? 0     let cornerTiles = [         board[0][0], board[0][3],         board[3][0], board[3][3]     ]     return cornerTiles.contains(where: { $0.value == maxTile }) ? 1.0 : 0.0 }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h4>\u041e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u044d\u0432\u0440\u0438\u0441\u0442\u0438\u043a \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0446\u0435\u043d\u043a\u0438 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0438 evaluate()<\/h4>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/72c\/151\/b32\/72c151b32b78211b981b040cb3cd7d94.png\" width=\"1024\" height=\"205\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/72c\/151\/b32\/72c151b32b78211b981b040cb3cd7d94.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f evaluate(board:)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func evaluateBoard(_ board: [[Tile]]) -&gt; Double {     let emptyWeight = 2.7     let smoothnessWeight = 0.1     let monotonicityWeight = 1.0     let maxTileCornerWeight = 1.0      let emptyTilesScore = Double(emptyTileCount(board)) * emptyWeight     let smoothnessScore = smoothness(board) * smoothnessWeight     let monotonicityScore = monotonicity(board) * monotonicityWeight     let maxTileInCornerScore = maxTileInCorner(board) * maxTileCornerWeight          return emptyTilesScore + smoothnessScore + monotonicityScore + maxTileInCornerScore }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d7b\/ad2\/9ca\/d7bad29ca52124367d11346dcf4dd792.png\" width=\"1024\" height=\"643\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d7b\/ad2\/9ca\/d7bad29ca52124367d11346dcf4dd792.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fbb\/3fb\/a1e\/fbb3fba1ef6522389bdce377adafce97.png\" width=\"1024\" height=\"615\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fbb\/3fb\/a1e\/fbb3fba1ef6522389bdce377adafce97.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 14. \u042d\u0432\u0440\u0438\u0441\u0442\u0438\u043a\u0430 \u0432 \u0432\u0438\u0434\u0435 Snake (\u0417\u043c\u0435\u044f) \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430<\/h3>\n<p>\u0414\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0438 \u0432 \u0432\u0438\u0434\u0435\u00a0<strong>Snake<\/strong>\u00a0\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b \u043d\u0430 \u0440\u0438\u0441\u0443\u043d\u043a\u0435:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/54c\/fbf\/943\/54cfbf943203aba5f29cd9f2784200aa.png\" width=\"1336\" height=\"678\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/54c\/fbf\/943\/54cfbf943203aba5f29cd9f2784200aa.png\"\/><\/figure>\n<div class=\"floating-image\">\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f2c\/53e\/04a\/f2c53e04a12ab0c4d20d7ef11e16a1b1.png\" alt=\"\u041c\u0430\u0442\u0440\u0438\u0446\u0430 \u0432\u0435\u0441\u043e\u0432 \u0434\u043b\u044f\u00a0Snake\u00a0\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0438\u0433\u0440\u044b 2048\" title=\"\u041c\u0430\u0442\u0440\u0438\u0446\u0430 \u0432\u0435\u0441\u043e\u0432 \u0434\u043b\u044f\u00a0Snake\u00a0\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0438\u0433\u0440\u044b 2048\" width=\"654\" height=\"608\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f2c\/53e\/04a\/f2c53e04a12ab0c4d20d7ef11e16a1b1.png\"\/><\/p>\n<div><figcaption>\u041c\u0430\u0442\u0440\u0438\u0446\u0430 \u0432\u0435\u0441\u043e\u0432 \u0434\u043b\u044f\u00a0<strong>Snake<\/strong>\u00a0\u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0438\u0433\u0440\u044b 2048<\/figcaption><\/div>\n<\/figure>\n<\/div>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e66\/89f\/827\/e6689f827531ce8cc7eb5561d5403ece.png\" width=\"1024\" height=\"197\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e66\/89f\/827\/e6689f827531ce8cc7eb5561d5403ece.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/20a\/a50\/fab\/20aa50fabf7f37bbd0befe753d4c74bd.png\" width=\"1024\" height=\"273\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/20a\/a50\/fab\/20aa50fabf7f37bbd0befe753d4c74bd.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/245\/4b3\/65b\/2454b365bc70a19c8f5656615c72f4db.png\" width=\"1024\" height=\"545\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/245\/4b3\/65b\/2454b365bc70a19c8f5656615c72f4db.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/00d\/2f6\/c21\/00d2f6c21f0677249751484ebcaaa764.png\" width=\"1024\" height=\"484\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/00d\/2f6\/c21\/00d2f6c21f0677249751484ebcaaa764.png\"\/><\/figure>\n<pre><code class=\"swift\">[15, 14, 13, 12] [8,  9,  10, 11] [7,  6,  5,  4] [0,  1,  2,  3]<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/43b\/a2e\/b49\/43ba2eb49b5d792c29ed69e0e966fb52.png\" width=\"1024\" height=\"304\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/43b\/a2e\/b49\/43ba2eb49b5d792c29ed69e0e966fb52.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f snakeHeuristic(board:) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func snakeHeuristic(_ board: [[Tile]]) -&gt; Double {     \/\/ Snake pattern score weights for each tile position     let snakePattern: [[Double]] = [         [15, 14, 13, 12],         [8,  9,  10, 11],         [7,  6,  5,  4],         [0,  1,  2,  3]     ]          var score = 0.0      \/\/ Evaluate how well the board follows the snake pattern     for row in 0..&lt;4 {         for col in 0..&lt;4 {             let tileValue = board[row][col].value             if tileValue &gt; 0 {             score += Double(log2(Double(tileValue))) * snakePattern[row][col]             }         }     }      return score }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5f7\/3df\/48e\/5f73df48e0f5d412c91ed13701421489.png\" width=\"1024\" height=\"391\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5f7\/3df\/48e\/5f73df48e0f5d412c91ed13701421489.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f evaluateBoard ( board: ) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func evaluateBoard (_ board: [[Tile]]) -&gt; Double {         let grid = board.map {$0.map{$0.value}}         let emptyCells = board.flatMap { $0 }.filter { $0.value == 0 }.count                let smoothWeight: Double = 0.1             let monoWeight: Double = 1.0             let emptyWeight: Double = 5.7             let maxWeight: Double = 1.0             let maxTileCornerWeight = 1.0                          return monoWeight *  monotonicity(grid)                  + smoothWeight * smoothness(grid)                  + emptyWeight * Double(emptyCells)                  + maxWeight * Double(grid.flatMap { $0 }.max() ?? 0)                   + maxTileCornerWeight * maxTileInCorner(board)                  + snakeHeuristic(grid)      }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/136\/b15\/b95\/136b15b95934ead6a16d1e18865761b2.png\" width=\"1024\" height=\"397\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/136\/b15\/b95\/136b15b95934ead6a16d1e18865761b2.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c4b\/053\/ac1\/c4b053ac19ee7d9b17947cdbee3856b1.png\" width=\"1024\" height=\"460\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c4b\/053\/ac1\/c4b053ac19ee7d9b17947cdbee3856b1.png\"\/><\/figure>\n<pre><code class=\"swift\">[2^15, 2^14, 2^13, 2^12] [2^8,  2^9,  2^10, 2^11] [2^7,  2^6,  2^5,  2^4] [2^0,  2^1,  2^2,  2^3]<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f snakeHeuristic(_ board: ) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func snakeHeuristic(_ board: [[Tile]]) -&gt; Double {     \/\/ Snake pattern score weights for each tile position based on powers of 2     let snakePattern: [[Double]] = [         [pow(2, 15), pow(2, 14), pow(2, 13), pow(2, 12)],         [pow(2, 8),  pow(2, 9),  pow(2, 10), pow(2, 11)],         [pow(2, 7),  pow(2, 6),  pow(2, 5),  pow(2, 4)],         [pow(2, 0),  pow(2, 1),  pow(2, 2),  pow(2, 3)]     ]          var score = 0.0      \/\/ Evaluate how well the board follows the snake pattern     for row in 0..&lt;4 {         for col in 0..&lt;4 {             let tileValue = board[row][col].value                 score += Double(tileValue) * snakePattern[row][col]         }     }      return score <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a51\/881\/16f\/a5188116f07872bdfb113a1a7ea05277.png\" width=\"1024\" height=\"733\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a51\/881\/16f\/a5188116f07872bdfb113a1a7ea05277.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ba5\/c63\/30d\/ba5c6330da0dc2d5b523d8e085f07ec4.png\" width=\"1024\" height=\"257\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ba5\/c63\/30d\/ba5c6330da0dc2d5b523d8e085f07ec4.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 15. \u041c\u0435\u0442\u043e\u0434 Monte Carlo \u043a\u0430\u043a \u0418\u0418 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c0b\/286\/887\/c0b2868870cd8def51f58c5c999f75d8.png\" width=\"1024\" height=\"187\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c0b\/286\/887\/c0b2868870cd8def51f58c5c999f75d8.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/19c\/259\/f8b\/19c259f8b197bf5980e7dfccc3e93a3d.png\" width=\"1024\" height=\"173\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/19c\/259\/f8b\/19c259f8b197bf5980e7dfccc3e93a3d.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c5f\/987\/692\/c5f987692a66a8597a580edaeffc8b5e.png\" width=\"1024\" height=\"690\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c5f\/987\/692\/c5f987692a66a8597a580edaeffc8b5e.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f monteCarloSearch (board:  simulations: depth: ) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func monteCarloSearch(board: [[Tile]], simulations: Int, depth: Int) -&gt; Direction {         var bestDirection: Direction = .up         var bestScore: Double = -Double.infinity                  \/\/ Iterate over all possible moves         for direction in Direction.allCases {             var totalScore: Double = 0                          \/\/ Simulate a number of games for each move             for _ in 0..&lt;simulations {                 var gameBoard = GameViewModel(matrix: board)                 let (moved, _) = gameBoard.slide(direction)                 if moved {                     \/\/ Play a random game starting from this move                   let score = randomGame(board: gameBoard.tiles, depth: depth)                     totalScore += score                 }             }                          \/\/ Calculate the average score for this move             let averageScore = totalScore \/ Double(simulations)                          \/\/ Select the move with the highest average score             if averageScore &gt; bestScore {                 bestScore = averageScore                 bestDirection = direction             }         }                  return bestDirection     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d4a\/020\/e97\/d4a020e97b1348e33efe383c7a9025a7.png\" width=\"1024\" height=\"191\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d4a\/020\/e97\/d4a020e97b1348e33efe383c7a9025a7.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f randomGame(board: depth:) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func randomGame(board:[[Tile]], depth: Int) -&gt; Double{         var moves = 0         var gameBoard = GameViewModel(matrix:board)         \/\/ Play until no more moves or reach max depth         while !isGameOver(gameBoard.tiles) &amp;&amp; moves &lt; depth {            let randomMove = Direction.allCases.randomElement()!             gameBoard.move (randomMove)             moves += 1        }                \/\/ Evaluate the board at the end of the game        return evaluateBoard(gameBoard.tiles)     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/97a\/007\/0a7\/97a0070a7b5f56903a294a90c9415056.png\" width=\"1024\" height=\"219\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/97a\/007\/0a7\/97a0070a7b5f56903a294a90c9415056.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u0444\u0443\u043d\u043a\u0446\u0438\u044f evaluateBoard( board: )<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>func evaluateBoard(_ board: [[Tile]]) -&gt; Double {     \/\/ Use a heuristic to evaluate the current state of the board     \/\/ For example: Sum of tiles, number of empty spaces, smoothness, monotonicity, etc. }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5bb\/1fa\/e10\/5bb1fae10f5064f3baf56382b283c45c.png\" width=\"1024\" height=\"215\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5bb\/1fa\/e10\/5bb1fae10f5064f3baf56382b283c45c.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f22\/db6\/171\/f22db617168e050acccaf117fbb2dfc8.png\" width=\"1024\" height=\"733\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f22\/db6\/171\/f22db617168e050acccaf117fbb2dfc8.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7da\/e3a\/637\/7dae3a63788939ff9e5ca058f0d8e442.png\" width=\"1024\" height=\"422\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7da\/e3a\/637\/7dae3a63788939ff9e5ca058f0d8e442.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 16. \u0423\u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 Monte Carlo \u043a\u0430\u043a \u0418\u0418 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/725\/fe7\/792\/725fe7792fd58bcaa177d29dedc92f72.png\" width=\"1024\" height=\"180\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/725\/fe7\/792\/725fe7792fd58bcaa177d29dedc92f72.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/1d0\/d33\/8ff\/1d0d338ff6842878c7c2efa57d9c2b6e.png\" width=\"1024\" height=\"223\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/1d0\/d33\/8ff\/1d0d338ff6842878c7c2efa57d9c2b6e.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cd9\/cf8\/669\/cd9cf8669f32ef8c5b1e9884b1aa5b30.png\" width=\"1024\" height=\"728\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cd9\/cf8\/669\/cd9cf8669f32ef8c5b1e9884b1aa5b30.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 biasedRandomGame(direction: board:depth: Int)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func biasedRandomGame(direction: Direction,board:[[Tile]], depth: Int) -&gt; Double{         var moves = 0         var gameBoard = GameViewModel(matrix:board)         \/\/ Play until no more moves or reach max depth         while !isGameOver(gameBoard.tiles) &amp;&amp; moves &lt; depth {            let biasedMoves = biasedMoveSelection(board: gameBoard.tiles)            let randomMove = biasedMoves.randomElement()!             gameBoard.move (randomMove)             moves += 1        }                \/\/ Evaluate the board at the end of the game        return evaluateBoard(gameBoard.tiles)     }  func biasedMoveSelection(board: [[Tile]]) -&gt; [Direction] {         var possibleMoves: [Direction] = []                  for direction in Direction.allCases {                  var gameBoard = GameViewModel(matrix:board)             let (moved, _) = gameBoard.slide(direction)             if moved {      \/\/ Prioritize moves that make the board smoother or merge tiles              if mergesTiles(gameBoard.tiles) || isBoardSmoother(gameBoard.tiles) {                     possibleMoves.append(direction)                 } else {                     possibleMoves.append(direction)                 }             }         }                  return possibleMoves.isEmpty ? Direction.allCases : possibleMoves     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/22c\/237\/0e7\/22c2370e74e99d080948bc61c16fb1ea.png\" width=\"1024\" height=\"366\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/22c\/237\/0e7\/22c2370e74e99d080948bc61c16fb1ea.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 randomGameWithEarlyStopping(board: depth: maxBadMoves:)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func randomGameWithEarlyStopping(board: [[Tile]], depth: Int, maxBadMoves: Int = 3) -&gt; Double {         var moves = 0         var badMoves = 0         var gameBoard = GameViewModel(matrix:board)          \/\/ Play until no more moves or reach max depth          while !isGameOver(gameBoard.tiles) &amp;&amp; moves &lt; depth {             let randomMove = Direction.allCases.randomElement()!             let (moved, _) = gameBoard.slide( randomMove)                          if moved {                 gameBoard.addNewTile()             } else {                 badMoves += 1                 if badMoves &gt;= maxBadMoves {                     break                 }             }             moves += 1         }                  return evaluateBoard(gameBoard.tiles)<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2c1\/429\/679\/2c1429679b43784c204d2eb2a90758d3.png\" width=\"1024\" height=\"379\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2c1\/429\/679\/2c1429679b43784c204d2eb2a90758d3.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 monteCarloSearchWithDynamicSimulations(board: maxSimulations: depth:<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func monteCarloSearchWithDynamicSimulations(board: [[Tile]], maxSimulations: Int, depth: Int) -&gt; Direction {     var bestDirection: Direction = .up     var bestScore: Double = -Double.infinity          \/\/ Adjust simulations based on the number of empty tiles     let emptyTilesCount = board.flatMap{$0}.filter{$0.value == 0}.count     let simulations = max(1, maxSimulations - emptyTilesCount * 2)          for direction in Direction.allCases {         var totalScore: Double = 0                  for _ in 0..&lt;simulations {             let gameBoard = GameViewModel(matrix: board)             let (moved, _ ) = gameBoard.slide( direction)                          if moved {                 let score = randomGame(board:gameBoard.tiles, depth: depth)                 totalScore += score             }         }                  let averageScore = totalScore \/ Double(simulations)         if averageScore &gt; bestScore {             bestScore = averageScore             bestDirection = direction         }     }          return bestDirection }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9f1\/47c\/460\/9f147c4603d8b2e5f117f6a688613afc.png\" width=\"1024\" height=\"306\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9f1\/47c\/460\/9f147c4603d8b2e5f117f6a688613afc.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 runSimulationsParallel(board:  direction: simulations: depth: ) <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func runSimulationsParallel(board: [[Tile]], direction: Direction, simulations: Int, depth: Int) -&gt; Double {     let queue = DispatchQueue.global(qos: .userInitiated)     let group = DispatchGroup()     var totalScore = 0.0          for _ in 0..&lt;simulations {         queue.async(group: group) {            var gameBoard = GameViewModel(matrix: board)            let (moved, _) = gameBoard.slide(direction)             if moved {               let score = randomGame(board: gameBoard.tiles, depth: depth)                 DispatchQueue.main.sync {                     totalScore += score                 }             }         }     }          group.wait()     return totalScore \/ Double(simulations) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c55\/b98\/a41\/c55b98a4104c968c93ce2df12edc38c9.png\" width=\"1024\" height=\"526\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c55\/b98\/a41\/c55b98a4104c968c93ce2df12edc38c9.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 evaluateBoard(board: )<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">func evaluateBoard(_ board: [[Tile]]) -&gt; Double {     let smoothness = calculateSmoothness(board)     let monotonicity = calculateMonotonicity(board)     let emptySpaces = Double(getEmptyTiles(board).count)          return smoothness + monotonicity + emptySpaces * 2 }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e1e\/e29\/6dd\/e1ee296dddee0bc8796570a2d4a24dd8.png\" width=\"1024\" height=\"277\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e1e\/e29\/6dd\/e1ee296dddee0bc8796570a2d4a24dd8.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/424\/0a0\/8f4\/4240a08f4b0050d95246b65612bced60.png\" width=\"1024\" height=\"579\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/424\/0a0\/8f4\/4240a08f4b0050d95246b65612bced60.png\"\/><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u044b\u0431\u0435\u0440\u0435\u043c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u0438\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u0440\u043e\u0441\u0438\u043c ChatGPT \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u0443\u044e \u0440\u0430\u043d\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>runSimulationsParallel(board:  direction: simulations: depth: )<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 <code>async await<\/code>:<\/p>\n<h3>\u0428\u0410\u0413 17. \u0421\u0434\u0435\u043b\u0430\u0439 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433\u00a0runSimulationsParallel\u00a0\u0441\u00a0async await<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/90f\/ad8\/314\/90fad8314f61968f587b4ec342891bdb.png\" width=\"1024\" height=\"796\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/90f\/ad8\/314\/90fad8314f61968f587b4ec342891bdb.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/065\/f81\/911\/065f819112cd08e49339c2d6843b4d33.png\" width=\"1024\" height=\"86\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/065\/f81\/911\/065f819112cd08e49339c2d6843b4d33.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/416\/233\/a67\/416233a6724af0ef7d2182beb9dfa91c.png\" width=\"1024\" height=\"372\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/416\/233\/a67\/416233a6724af0ef7d2182beb9dfa91c.png\"\/><\/figure>\n<pre><code class=\"swift\">func runSimulationsParallel(board: [[Tile]], direction: Direction, simulations: Int, depth: Int) async -&gt; Double {     var totalScore = 0.0          \/\/ Create an array of tasks for parallel execution     await withTaskGroup(of: Double.self) { taskGroup in         for _ in 0..&lt;simulations {             taskGroup.addTask {                let gameBoard = Game(matrix: matrix)                 let (moved, _) = gameBoard.slide(direction)                                  if moved {                   let score = randomGame(board:gameBoard.tiles, depth: depth)                     return score                 } else {                     return 0.0 \/\/ If no move is made, return a score of 0                 }             }         }                  \/\/ Collect all the results from the tasks         for await score in taskGroup {             totalScore += score         }     }          return totalScore \/ Double(simulations) }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d35\/151\/8fb\/d351518fb841915deb06c140aff12bfd.png\" width=\"1024\" height=\"872\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d35\/151\/8fb\/d351518fb841915deb06c140aff12bfd.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/443\/ee0\/e2e\/443ee0e2e273e2b1e6106df03a1c82a2.png\" width=\"1024\" height=\"308\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/443\/ee0\/e2e\/443ee0e2e273e2b1e6106df03a1c82a2.png\"\/><\/figure>\n<h3>\u0428\u0410\u0413 18. \u041f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u0438\u0437\u043c expectimax \u0441\u00a0async await<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/398\/afd\/dd4\/398afddd4649c01ad0dba632ea0fc45f.png\" width=\"1024\" height=\"149\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/398\/afd\/dd4\/398afddd4649c01ad0dba632ea0fc45f.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/671\/3a5\/e9e\/6713a5e9eb24a18d079f0f7ec14ad75a.png\" width=\"1024\" height=\"368\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/671\/3a5\/e9e\/6713a5e9eb24a18d079f0f7ec14ad75a.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fd7\/69f\/0f5\/fd769f0f510a7ad9b8b75eb2ef1c75bc.png\" width=\"1024\" height=\"821\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fd7\/69f\/0f5\/fd769f0f510a7ad9b8b75eb2ef1c75bc.png\"\/><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 expectimaxAsyn (grid: depth: isAITurn)<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\"> \/\/ Asynchronous expectimax algorithm with improved parallelism    func expectimaxAsyn(grid: [[Tile]], depth: Int, isAITurn: Bool) async -&gt; Double {                  \/\/ Base case: return the board evaluation if depth is 0 or game is over         if depth == 0 || isGameOver (grid.map {$0.map{$0.value}}){           \/\/ return evaluateBoard(grid.map {$0.map{$0.value}})             return evaluateBoard(grid)         }         if isAITurn {             \/\/------             \/\/ Player's turn (maximize the score)             var maxScore = -Double.infinity                          \/\/ Use task group for parallel evaluation of all directions             return await withTaskGroup(of: Double.self) { group in                 for direction in Direction.allCases {                     group.addTask {                         var game = Game (matrix: grid) \/\/ Initialize Game                         let (moved, _) = game.slide( direction)                         if moved {                             return      await expectimaxAsyn (grid: game.tiles, depth: depth - 1, isAITurn: false)                         }                         return -Double.infinity                     }                 }                                  for await result in group {                     maxScore = max(maxScore, result)                 }                 return maxScore             }             \/\/------                     } else {             \/\/ AI's turn (chance node)         \/\/    var expectedScore = 0.0             let emptyTiles = grid.flatMap { $0 }.filter { $0.value == 0 }             \/\/ If no empty tiles, the game is over             if emptyTiles.isEmpty {              \/\/  return evaluateBoard(grid.map {$0.map{$0.value}})                 return evaluateBoard(grid)             }             \/\/ Limit parallelism at deeper levels to avoid overwhelming system             if depth &gt; 4 {\/\/3 {                 var expectedValue = 0.0                 for tile in emptyTiles {                     var boardWith2 = grid                     boardWith2[tile.position.row][tile.position.col].value = 2                     let valueFor2 =        await expectimaxAsyn(grid: boardWith2, depth: depth - 1, isAITurn: true)                                          var boardWith4 = grid                     boardWith4[tile.position.row][tile.position.col].value = 4                     let valueFor4 =        await expectimaxAsyn(grid: boardWith4, depth: depth - 1, isAITurn: true)                     expectedValue += 0.9 * valueFor2 + 0.1 * valueFor4                 }                 return expectedValue \/ Double(emptyTiles.count)             } else {                 \/\/ Use task group for parallel execution in shallower levels                 return await withTaskGroup(of: Double.self) { group in                     var expectedValue = 0.0                     for tile in emptyTiles {                         group.addTask {                             var boardWith2 = grid                     boardWith2[tile.position.row][tile.position.col].value = 2                             return  await expectimaxAsyn(grid: boardWith2, depth: depth - 1, isAITurn: true) * 0.9                         }                         group.addTask {                             var boardWith4 = grid                                                              boardWith4[tile.position.row][tile.position.col].value = 4                             return  await expectimaxAsyn(grid: boardWith4, depth: depth - 1, isAITurn: true) * 0.1                         }                     }                                          for await result in group {                         expectedValue += result                     }                     return expectedValue \/ Double(emptyTiles.count)                 }             }         }     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/162\/8e6\/f46\/1628e6f462981789a79d581d1670bb4b.png\" width=\"1024\" height=\"783\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/162\/8e6\/f46\/1628e6f462981789a79d581d1670bb4b.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f2b\/1c6\/c6c\/f2b1c6c6ce5ebc87e64fbbb588d93d4d.png\" width=\"1024\" height=\"328\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f2b\/1c6\/c6c\/f2b1c6c6ce5ebc87e64fbbb588d93d4d.png\"\/><\/figure>\n<pre><code class=\"swift\">\/\/ MARK: -  ExpectimaxAsync AI   func bestExpectimaxAsync (depth: Int, matrix: [[Tile]]) async -&gt; Direction {         var bestDirection = Direction.right         var bestScore: Double = -Double.infinity                        \/\/ for move in possibleMoves {         for direction in Direction.allCases {             var model = Game (matrix: matrix) \/\/ Initialize Game           \/\/  let (moved, _ ) = model.slide(move)             let (moved, _ ) = model.slide(direction)             if moved {                 let newScore =      await expectimaxAsyn (grid: model.tiles, depth: depth ,  isAITurn: false)                 if newScore &gt; bestScore {                     bestScore = newScore                    \/\/ bestMove = move                     bestDirection = direction                 }             }         }         return bestDirection     }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e12\/50f\/b72\/e1250fb7254edc74fc622c4ec1e9ce37.png\" width=\"1024\" height=\"158\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e12\/50f\/b72\/e1250fb7254edc74fc622c4ec1e9ce37.png\"\/><\/figure>\n<pre><code class=\"swift\"> func bestMoveDirectionExpectimaxAsync() async -&gt; Direction {     let direction = await aiGame.bestExpectimaxAsync(depth: 5, matrix: tiles)         return direction   }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5e1\/522\/0e4\/5e15220e4f56f3d5c7235f695abd2186.png\" width=\"1024\" height=\"62\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5e1\/522\/0e4\/5e15220e4f56f3d5c7235f695abd2186.png\"\/><\/figure>\n<pre><code class=\"swift\">func expectimaxAsyncAIMove() {         Task{             let bestDirection =  await game.bestMoveDirectionExpectimaxAsync()             game.move(bestDirection)          }   }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d32\/c30\/890\/d32c3089016126b3c28caec4c248a77f.png\" width=\"1024\" height=\"76\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d32\/c30\/890\/d32c3089016126b3c28caec4c248a77f.png\"\/><\/figure>\n<pre><code class=\"swift\">.onReceive(timer){ value in           if isAIPlaying  &amp;&amp; !viewModel.isGameOver {               if selectedAlgorithm == Algorithm.MonteCarloAsync {                   viewModel.monteCarloAsyncAIMove()               } else if selectedAlgorithm == Algorithm.Expectimax1 {                   viewModel.expectimaxAsyncAIMove()               } else {                     viewModel.executeAIMove()               }            }    }<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/445\/206\/316\/445206316a0000d9db4c51b9e90a1298.png\" width=\"1024\" height=\"272\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/445\/206\/316\/445206316a0000d9db4c51b9e90a1298.png\"\/><\/figure>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/h2>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f ChatGPT \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 iOS  \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0441\u0442\u0430\u043b\u0430 \u0431\u043e\u043b\u0435\u0435 \u043e\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u043e\u0439. \u041d\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u0432\u043b\u0435\u043a\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435 \u0432\u0435\u0449\u0438 \u0442\u0438\u043f\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438 \u0438\u043b\u0438 \u043c\u0435\u043d\u044e \u043d\u0430 UI \u2014 \u0430 \u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0445 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f\u0445. \u0422\u043e \u0435\u0441\u0442\u044c \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c \u0438 \u0432\u0430\u0436\u043d\u043e\u043c. \u042d\u0442\u043e \u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0431\u043e\u043b\u0435\u0435 \u0440\u0438\u0441\u043a\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0435, \u043d\u0435 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044f \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439. \u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438 \u043f\u0440\u043e\u0441\u044b\u043f\u0430\u0435\u0442\u0441\u044f \u0447\u0443\u0432\u0441\u0442\u0432\u043e \u0430\u0437\u0430\u0440\u0442\u0430 \u0438 \u043e\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441 ChatGPT \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0448\u044c \u0438\u0441\u0442\u0438\u043d\u043d\u043e\u0435 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435.<\/p>\n<p>\u0427\u0442\u043e \u0436\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e?<\/p>\n<ol>\n<li>\n<p>ChatGPT \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043f\u043e\u043b\u043d\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u201c\u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0430\u043c\u0438\u201d \u0434\u043b\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u044b\u0445 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u043d\u043e \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430\u043b\u044c\u0448\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0440\u0430\u0437\u0432\u0438\u0432\u0430\u0442\u044c, \u0441\u0441\u044b\u043b\u0430\u044f\u0441\u044c \u043d\u0430 \u044d\u0442\u0438 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0438 \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0430\u0437\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p> ChatGPT \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 <code>var<\/code>, \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442 <code>let<\/code> \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 <code>func<\/code>, \u0447\u0442\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u0447\u0442\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0438 \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0430\u0441 \u043e\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u201c\u043b\u043e\u043c\u0430\u0442\u044c \u0433\u043e\u043b\u043e\u0432\u0443\u201d \u043d\u0430\u0434 \u044d\u0442\u0438\u043c. \u0418 \u0432\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043d\u0438\u0445 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0434\u0438\u0430\u043b\u043e\u0433\u0435 \u0441 ChatGPT.<\/p>\n<\/li>\n<li>\n<p>ChatGPT 4-o \u0432 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u0435 \u0432\u043b\u0430\u0434\u0435\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c\u0438 \u0432\u044b\u0441\u0448\u0435\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f\u043c\u0438 (<code>map<\/code>,<strong> <\/strong><code>flatMap<\/code>, <code>compactMap<\/code>, <code>filter<\/code>, <code>allSatisfy<\/code>) \u0432 Swift \u0438 \u0432\u0441\u044e\u0434\u0443 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u0445, \u0438\u043d\u043e\u0433\u0434\u0430 \u0432 \u0441\u0430\u043c\u044b\u0445 \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f\u0445 \u0438 \u0441\u0430\u043c\u044b\u043c \u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438\u044f\u0442\u043d\u043e \u0443\u0434\u0438\u0432\u043b\u044f\u0435\u0442.<\/p>\n<\/li>\n<li>\n<p> \u041f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u0432\u043b\u0430\u0434\u0435\u0435\u0442 <a href=\"https:\/\/docs.google.com\/document\/d\/16o_x7bcbbkgSNJq-vKr8650Ei7rFjVSprBIj8ac_Fi4\/edit?usp=drive_link\" rel=\"noopener noreferrer nofollow\"><u>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439 MVVM<\/u><\/a> (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438, \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b\u0430), \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044f \u043a\u0430\u043a \u043d\u0435\u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c, \u043a\u043e\u0433\u0434\u0430 <code>ViewModel<\/code> \u0438 <code>Model<\/code> \u0432 \u043e\u0434\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 (\u0441 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u043c <code>ObservableObject<\/code> \u0438\u043b\u0438 \u043d\u043e\u0432\u044b\u043c \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u043c <code>@Observable<\/code>), \u0442\u0430\u043a \u0438 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c: <code>Model<\/code> \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 <code>ViewModel<\/code> \u0438 <code>View<\/code>. \u041b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u043e\u0442 \u043e\u0434\u043d\u043e\u0439 \u043a \u0434\u0440\u0443\u0433\u043e\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0434\u0430\u0451\u0442 \u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u0432\u0435\u0442\u044b \u043f\u043e \u0438\u0445 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u0438 \u0445\u0440\u0430\u043d\u0438\u0442 \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0439 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0439 \u0441\u0435\u0441\u0441\u0438\u0438 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0435\u0433\u043e \u044d\u0442\u0430\u043f\u044b.<\/p>\n<\/li>\n<li>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0442 \u043a\u043e\u0434.<\/p>\n<\/li>\n<li>\n<p> \u0413\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 Unit \u0442\u0435\u0441\u0442\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c XCTest.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u043e\u044f\u0432\u043b\u044f\u0435\u0442 \u0444\u0430\u043d\u0442\u0430\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u044d\u0440\u0443\u0434\u0438\u0446\u0438\u044e \u0432 \u0447\u0430\u0441\u0442\u0438 \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0434\u043b\u044f \u0438\u0433\u0440 \u0442\u0438\u043f\u0430 2048.<\/p>\n<\/li>\n<\/ol>\n<p>\u0418 \u043c\u043d\u043e\u0433\u043e \u0447\u0435\u0433\u043e \u0435\u0449\u0435 \u2026.<\/p>\n<p>\u0412\u0441\u0435 \u0441\u0432\u043e\u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 ChatGPT \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u043c\u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u043c\u0438 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0434\u0430\u0441\u0442 \u0432\u0430\u043c \u043d\u0438 \u043e\u0434\u0438\u043d \u043a\u0443\u0440\u0441 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f. \u0422\u0430\u043a \u0447\u0442\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0438\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c\u00a0 \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0435 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u044f\u0437\u044b\u043a\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Swift\u00a0 \u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443 SwiftUI (\u043c\u043d\u0435 \u044d\u0442\u043e \u0432\u0440\u043e\u0434\u0435 \u043a\u0430\u043a \u043d\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u043e\u0441\u044c, \u043d\u043e  \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u043b\u0430 \u0447\u0442\u043e-\u0442\u043e \u043d\u043e\u0432\u043e\u0435!!!).\u00a0\u0415\u0441\u043b\u0438 \u0432\u044b \u0438\u0437\u0443\u0447\u0430\u0435\u0442\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 Swift \u0438 SwiftUI, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043c\u043e\u0439 \u043f\u0443\u0442\u044c. \u0412\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 \u043a\u043e\u043b\u043e\u0441\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u043f\u044b\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<p>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438:<\/p>\n<ul>\n<li>\n<p>\u0425\u043e\u0442\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0435\u0448\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0441\u0441\u0438\u0438, \u043a\u043e\u0434 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043f\u043e \u043a\u0443\u0441\u043e\u0447\u043a\u0430\u043c, \u044d\u0442\u043e \u0432\u0430\u043c \u043d\u0435<a href=\"https:\/\/claude.ai\/\" rel=\"noopener noreferrer nofollow\"> Claude 3.5 Sonnet.<\/a> \u041e\u0434\u043d\u0430\u043a\u043e \u043a \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0435\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f &#8212; ChatGPT 4 Canvas, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u0435\u0440\u0436\u0438\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u043d\u043e \u044f \u0435\u0433\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u043e\u0433\u0434\u0430 &#171;\u0443\u0432\u0438\u043b\u0438\u0432\u0430\u0435\u0442&#187; \u043e\u0442 \u043f\u0440\u044f\u043c\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u043e\u043f\u0440\u043e\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0427\u0430\u0441\u0442\u043e \u0434\u0430\u0451\u0442 \u043a\u043e\u0434 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438: \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b <code>ObservableObject<\/code> \u0432\u043c\u0435\u0441\u0442\u043e \u043c\u0430\u043a\u0440\u043e\u0441\u0430 <a class=\"mention\" href=\"\/users\/observable,\">@Observable,<\/a><code>GCD<\/code> (Grand Central Dispatch) \u0432\u043c\u0435\u0441\u0442\u043e <code>async<\/code> <code>await<\/code>, \u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u043d\u0430 \u044d\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0438 ChatGPT  \u0432\u0435\u043b\u0438\u043a\u043e\u043b\u0435\u043f\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u043a\u043e\u0434\u0430 \u0438 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0435 \u043c\u0435\u0436\u0434\u0443 \u043d\u043e\u0432\u044b\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c \u0438 \u0441\u0442\u0430\u0440\u044b\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u043d\u0430\u0434 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438\u0433\u0440\u044b 2048 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e chatGPT \u043c\u043d\u0435 \u043d\u0438 \u0440\u0430\u0437\u0443 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a Google \u0438\u043b\u0438 StackOverFlow, \u0442\u0430\u043a \u0447\u0442\u043e ChatGPT \u0432\u043f\u043e\u043b\u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0434\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<\/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\/851904\/\"> https:\/\/habr.com\/ru\/articles\/851904\/<\/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<p>\u042f \u0445\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0430\u043c\u0438 \u043e\u043f\u044b\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f &#171;\u0441 \u043d\u0443\u043b\u044f&#187;  iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e\u0439 \u0438\u0433\u0440\u044b 2048 \u0441 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0418\u0418 (\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0430) \u0432 SwiftUI \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ChatGPT .<\/p>\n<p>\u0412 \u0441\u0432\u043e\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u0438\u0433\u0440\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0436\u0435\u0441\u0442\u043e\u0432 (\u0432\u0432\u0435\u0440\u0445, \u0432\u043d\u0438\u0437, \u0432\u043f\u0440\u0430\u0432\u043e, \u0432\u043b\u0435\u0432\u043e),\u00a0 \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0438\u0433\u0440\u0430 \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0439 \u0438\u0433\u0440\u044b 2048 \u043c\u043e\u0436\u043d\u043e \u0437\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u043e\u0435 \u0432\u0440\u0435\u043c\u044f, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c\u00a0 \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u0435\u043d \u043a\u0430\u0436\u0434\u043e\u043c\u0443. \u041d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438\u0433\u0440\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u044e\u0442 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0445 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048, \u0442\u043e \u0435\u0441\u0442\u044c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0418\u0418, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0433 \u0431\u044b \u0438\u0433\u0440\u0430\u0442\u044c \u0432 \u044d\u0442\u0443 \u0438\u0433\u0440\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0447\u0435\u0442 \u0438\u0433\u0440\u044b \u0432 \u0440\u0430\u0437\u0443\u043c\u043d\u044b\u0435 \u0441\u0440\u043e\u043a\u0438. <\/p>\n<p>\u041c\u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438\u0433\u0440\u0443 2048 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 SwiftUI, \u043f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u0435\u0433\u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u0439 \u0438 \u043c\u043e\u0449\u043d\u043e\u0439 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0438 \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u044b\u043c \u0431\u044b\u0441\u0442\u0440\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u043c , a \u0442\u0430\u043a\u0436\u0435\u00a0 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u201c\u0440\u0443\u0447\u043d\u043e\u0439\u201d \u0441\u043f\u043e\u0441\u043e\u0431 \u0438\u0433\u0440\u044b, \u043a\u043e\u0433\u0434\u0430 \u0412\u044b \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0438\u0442\u0435 \u0442\u0435\u043c, \u043a\u0430\u043a\u0438\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0445\u043e\u0434: \u0432\u0432\u0435\u0440\u0445, \u0432\u043d\u0438\u0437, \u0432\u043b\u0435\u0432\u043e \u0438 \u0432\u043f\u0440\u0430\u0432\u043e, \u043d\u043e \u0438 \u0440\u044f\u0434 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0441 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0435\u0439 (<a href=\"https:\/\/habr.com\/ru\/companies\/edison\/articles\/437118\/\" rel=\"noopener noreferrer nofollow\">\u043c\u0435\u0442\u043e\u0434\u0430 \u041c\u043e\u043d\u0442\u0435-\u041a\u0430\u0440\u043b\u043e<\/a>,\u00a0<a href=\"https:\/\/habr.com\/ru\/companies\/edison\/articles\/474680\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u0439 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u044c\u044f\u043c (Minimax, Expectimax<\/a>) ), \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0445 \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0445\u043e\u0434\u044b &#8212; \u0432\u0432\u0435\u0440\u0445, \u0432\u043d\u0438\u0437, \u0432\u043b\u0435\u0432\u043e \u0438 \u0432\u043f\u0440\u0430\u0432\u043e &#8212; \u0438 \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f\u00a0 \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 2048 \u0438 \u0431\u043e\u043b\u0435\u0435 (\u044d\u0442\u0438 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b \u0438 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u043c\u0438 \u201c\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0430\u201d (\u0418\u0418)).\u00a0\u00a0\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0418\u0418 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u043f\u0435\u0440\u0435\u0434 \u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0438, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0440\u0435\u0448\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0445\u043e\u0434 \u043e\u043d \u0445\u043e\u0447\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438.  <\/p>\n<p>2048 &#8212; \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u0438\u0433\u0440\u0430, \u0438 \u043c\u043d\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442\u044c ChatGPT \u0435\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430, \u043e\u043d \u0441\u0430\u043c \u0432\u0441\u0451 \u043f\u0440\u043e \u043d\u0435\u0451 \u0437\u043d\u0430\u0435\u0442. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e ChatGPT \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d \u043e\u0431 \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430\u0445 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043d\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c ChatGPT \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0435\u0448\u0430\u0435\u043c\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438. \u0418 \u043e\u043d \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b \u043c\u043d\u0435 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u043a\u0438\u0445 \u043d\u0435\u043e\u0440\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0434\u043e\u043b\u0433\u043e \u0432\u044b\u0438\u0441\u043a\u0438\u0432\u0430\u0442\u044c \u0432 \u043d\u0430\u0443\u0447\u043d\u044b\u0445 \u0436\u0443\u0440\u043d\u0430\u043b\u0430\u0445.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u044b \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0441\u043c\u043e\u0433\u043b\u0438 \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u044f \u043a\u0440\u0430\u0442\u043a\u043e \u043d\u0430\u043f\u043e\u043c\u043d\u044e \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438\u0433\u0440\u044b 2048.<\/p>\n<p>\u0421\u0430\u043c\u0430 \u0438\u0433\u0440\u0430 \u043f\u0440\u043e\u0441\u0442\u0430. \u0412\u0430\u043c \u0434\u0430\u0435\u0442\u0441\u044f \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c\u00a0<strong>4<\/strong>\u00d7<strong>4<\/strong>, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0447\u0438\u0441\u043b\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f.\u00a0<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0420\u0438\u0441.1 \u041f\u0440\u0438\u043c\u0435\u0440 \u0445\u043e\u0434\u0430 \u0432 2048. \u041f\u043e\u0441\u043b\u0435 \u0445\u043e\u0434\u0430 \u201c\u0441\u0434\u0432\u0438\u0433 \u0432\u043b\u0435\u0432\u043e\u201d (left) \u043d\u0430 \u043b\u0435\u0432\u043e\u0439 \u0434\u043e\u0441\u043a\u0435. \u0414\u043e\u0441\u043a\u0430 \u0441\u043b\u0435\u0432\u0430 \u0441\u0442\u0430\u043d\u0435\u0442 \u0442\u043e\u0439, \u0447\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u0440\u0438\u0441. \u0441\u043f\u0440\u0430\u0432\u0430.<\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0438\u0441\u043b\u0430 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0441\u0442\u0435\u043f\u0435\u043d\u044c\u044e \u0434\u0432\u043e\u0439\u043a\u0438. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0435\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u043d\u043e\u043c\u0435\u0440\u0430\u043c\u0438\u00a0<strong>2<\/strong>\u00a0\u0438\u043b\u0438\u00a0<strong>4<\/strong>. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043c\u0435\u043d\u044f\u0442\u044c \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435, \u043d\u0430\u0436\u0438\u043c\u0430\u044f \u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 \u0441\u043e \u0441\u0442\u0440\u0435\u043b\u043a\u0430\u043c\u0438 &#8212;<strong>\u00a0\u0432\u0432\u0435\u0440\u0445<\/strong>,<strong>\u00a0\u0432\u043d\u0438\u0437<\/strong>,\u00a0<strong>\u0432\u043f\u0440\u0430\u0432\u043e<\/strong>,\u00a0<strong>\u0432\u043b\u0435\u0432\u043e<\/strong>\u00a0&#8212; \u0438 \u0432\u0441\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u044c\u0441\u044f \u0432 \u044d\u0442\u043e\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438, \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043b\u0438\u0442\u043a\u043e\u0439, \u043b\u0438\u0431\u043e \u0433\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u0441\u0435\u0442\u043a\u0438. \u0415\u0441\u043b\u0438 \u0434\u0432\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u0447\u0438\u0441\u043b\u0430\u043c\u0438 \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f, \u043e\u043d\u0438 \u0441\u043e\u043b\u044c\u044e\u0442\u0441\u044f \u0432 \u043d\u043e\u0432\u0443\u044e \u043f\u043b\u0438\u0442\u043a\u0443 \u0441 \u0438\u0445 \u0441\u0443\u043c\u043c\u043e\u0439. \u041d\u043e\u0432\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0441\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043e\u0441\u0435\u0434\u043d\u0435\u0439 \u043f\u043b\u0438\u0442\u043a\u043e\u0439 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f. \u041f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u0430\u044f \u043f\u043b\u0438\u0442\u043a\u0430 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 2 \u0438\u043b\u0438 4 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u043f\u0443\u0441\u0442\u044b\u0445 \u043f\u043b\u0438\u0442\u043e\u043a, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0438\u0433\u0440\u043e\u043a \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u043e\u0432\u044b\u0439 \u0445\u043e\u0434.<\/p>\n<p>\u0426\u0435\u043b\u044c \u0438\u0433\u0440\u044b \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0441\u0442\u0438\u0447\u044c \u043f\u043b\u0438\u0442\u043a\u0438 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 2048, \u043d\u043e \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0448\u0438\u0440\u043e\u043a\u043e \u0438 \u0434\u043e\u0441\u0442\u0438\u0433\u0430\u0442\u044c \u043f\u043b\u0438\u0442\u043a\u0443 \u0441 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c \u0447\u0438\u0441\u043b\u043e\u043c. \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u0434\u0441\u0447\u0435\u0442\u0430 \u043e\u0447\u043a\u043e\u0432, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c\u0430\u044f \u043a \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0445\u043e\u0434\u0443. \u0421\u0447\u0435\u0442 \u0438\u0433\u0440\u043e\u043a\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u043d\u0443\u043b\u044f \u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0434\u0432\u0435 \u043f\u043b\u0438\u0442\u043a\u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442\u0441\u044f, \u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u043e\u0439 \u043f\u043b\u0438\u0442\u043a\u0438. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442 \u043f\u0443\u0441\u0442\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u0438 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0445 \u0445\u043e\u0434\u043e\u0432, \u0442\u043e \u0438\u0433\u0440\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f.\u00a0<\/p>\n<p>\u0418\u0442\u0430\u043a, \u043c\u043e\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0430\u0441\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u0432\u0438\u0436\u043e\u043a \u0438\u0433\u0440\u044b 2048 \u043d\u0430 Swift, \u043d\u043e \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c UI c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SwiftUI, a \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0418\u0418 (\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b Expectimax \u0438 Monte Carlo) \u0432 \u0438\u0433\u0440\u0435 2048. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u044f \u0445\u043e\u0442\u0435\u043b\u0430 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 ChatGPT.<\/p>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0430\u043f\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0430\u043a\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e ChatGPT:<\/p>\n<ol>\n<li>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b \u0431\u0435\u0437 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 UI (\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u043f\u043b\u0438\u0442\u043e\u043a, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043b\u0438\u0442\u043e\u043a \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435).<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 AI (\u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b Greedy, Expectimax \u0438 MonteCarlo) \u0432 \u0438\u0433\u0440\u0443 2048 c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c.<\/p>\n<p>\u041d\u0430 \u0442\u0440\u0435\u0442\u044c\u0435\u043c \u044d\u0442\u0430\u043f\u0435 \u044f  \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430 \u043e\u0442 ChatGPT  \u0434\u0432\u0430 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430 \u0418\u0418 &#8212;\u00a0<strong>Expectimax<\/strong>\u00a0\u0438\u00a0<strong>Monte Carlo<\/strong>\u00a0&#8212; \u0438 \u0438\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b &#8212; \u043f\u043b\u0438\u0442\u043a\u0438 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438\u00a0\u00a0<strong>4096<\/strong>\u00a0\u0438\u00a0<strong>8092<\/strong>.<\/p>\n<figure class=\"\">\n<div><figcaption>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Expectimax \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<\/li>\n<\/ol>\n<figure class=\"\">\n<div><figcaption>\u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c Monte Carlo \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0438<\/figcaption><\/div>\n<\/figure>\n<p>\u0417\u0430\u043c\u0435\u0442\u044c\u0442\u0435, \u043a\u0430\u043a\u043e\u0439 \u0440\u0430\u0437\u043d\u044b\u0439 \u0440\u0438\u0441\u0443\u043d\u043e\u043a \u0438\u0433\u0440\u044b \u0443 \u044d\u0442\u0438\u0445 \u0434\u0432\u0443\u0445 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432, \u0441\u0442\u0440\u0435\u043c\u044f\u0449\u0438\u0445\u0441\u044f \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u0442\u043e\u043c\u0443 \u0436\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0443.<\/p>\n<p>\u042f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e ChatGPT 4-o.mini (\u043d\u0435 \u0441\u0430\u043c\u0443\u044e \u043c\u043e\u0449\u043d\u0443\u044e). \u0412\u0441\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0437\u0430\u0434\u0430\u0432\u0430\u043b\u0438\u0441\u044c \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u043e\u0442 ChatGPT 4-o.mini \u0442\u043e\u0436\u0435 \u0431\u044b\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u044b \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c, \u043d\u043e \u0432\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u044b \u0441\u0430\u043c\u0438\u043c \u0436\u0435 ChatGPT \u0434\u043b\u044f \u0432\u0430\u0441 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u0438\u0439.\u00a0<\/p>\n<p>\u0412 \u043f\u043b\u0430\u043d\u0435 \u0434\u0432\u0438\u0436\u043a\u0430 \u0438\u0433\u0440\u044b 2048 \u0438 UI \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439 ChatGPT \u0434\u0430\u043b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0447\u0435\u043d\u044c \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u0441 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u0445\u043e\u0442\u044f \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0435 \u043e\u0431\u043e\u0448\u043b\u043e\u0441\u044c. \u0423 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e \u043e\u0448\u0438\u0431\u043e\u043a, \u043d\u043e \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u0437\u0430\u0432\u0443\u0430\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0442\u0430\u043a-\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0439\u0442\u0438. \u0412\u043e\u0442 \u0442\u043e\u0433\u0434\u0430 \u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u0442\u044c \u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0435\u0441\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 ChatGPT \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e. <\/p>\n<p>\u0412 \u043f\u043b\u0430\u043d\u0435 \u0418\u0418 \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048 ChatGPT \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0440\u0430\u0437\u0438\u043b \u043c\u0435\u043d\u044f \u0441\u0432\u043e\u0435\u0439 \u044d\u0440\u0443\u0434\u0438\u0446\u0438\u0435\u0439, \u043e\u043d \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u043b \u043c\u043d\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u0442\u0430\u043a\u0438\u0435  \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b, \u043a\u0430\u043a Expextimax \u0438 Monte Carlo \u0441\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0437\u043d\u0430\u0447\u0438\u043c\u043e\u0433\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430. \u0418 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0432\u0435\u0442\u044b, \u0432\u0441\u0435 \u044d\u0442\u043e \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043a\u043e\u0434\u043e\u043c. \u0412 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Swift \u043c\u043d\u043e\u0433\u043e\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u043c, \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438 \u0433\u043b\u0443\u0431\u043e\u043a\u0438\u0445 \u0434\u0435\u0440\u0435\u0432\u044c\u0435\u0432 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432 \u0438\u0433\u0440\u0435 2048.  <\/p>\n<p>\u0415\u0449\u0435 \u0431\u043e\u043b\u0435\u0435 \u0446\u0435\u043d\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043c\u043e\u0436\u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043d\u0430 Swift \u0438 SwiftUI \u043d\u0435 \u0445\u0443\u0436\u0435 <a href=\"https:\/\/bestkora.com\/IosDeveloper\/ios-swiftui-2023\/\" rel=\"noopener noreferrer nofollow\">\u0421\u0442\u044d\u043d\u0444\u043e\u0440\u0434\u0441\u043a\u043e\u0433\u043e \u043a\u0443\u0440\u0441\u0430<\/a>. <\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 ChatGPT \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 iOS  \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0432 3-\u0445 \u043f\u043e\u0441\u0442\u0430\u0445 \u043d\u0430 \u043c\u043e\u0435\u043c \u0441\u0430\u0439\u0442\u0435: <\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/bestkora.com\/IosDeveloper\/test\/%E2%86%97\" rel=\"noopener noreferrer nofollow\">iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0432 SwiftUI\u00a0 \u0441 ChatGPT 4-o. \u0427\u0430\u0441\u0442\u044c 1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435. \u041b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b 2048.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/bestkora.com\/IosDeveloper\/%D0%B0%D0%B7%D0%B0%D1%80%D1%82%D0%BD%D0%B0%D1%8F-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0-ios-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8%D0%B3%D1%80%D1%8B\/%E2%86%97\" rel=\"noopener noreferrer nofollow\">iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u0433\u0440\u044b 2048 \u0432 SwiftUI\u00a0 \u0441 ChatGPT 4-o. \u0427\u0430\u0441\u0442\u044c 2. \u0410\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0438 UI.<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/bestkora.com\/IosDeveloper\/ios-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8%D0%B3%D1%80%D1%8B-2048-%D0%B2-swiftui-%D1%81-chatgpt-%D1%87%D0%B0%D1%81%D1%82%D1%8C-3-%D0%B8%D0%B8-ai\/\" rel=\"noopener noreferrer nofollow\">iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b 2048 \u0432 SwiftUI \u0441 ChatGPT. \u0427\u0430\u0441\u0442\u044c 3. \u0418\u0418 (AI) \u0434\u043b\u044f \u0438\u0433\u0440\u044b 2048.<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0410 \u043a\u043e\u0434 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/Game2048ChatGPT\" rel=\"noopener noreferrer nofollow\">GitHub<\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u043b\u0438\u0448\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430, \u0447\u0442\u043e\u0431\u044b \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u043f\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c ChatGPT \u043a\u0430\u043a \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0442\u0430\u043a \u0438 \u043f\u0440\u0438 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0438.<\/p>\n<h2>\u041b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b 2048<\/h2>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043a ChatGPT:<\/p>\n<h3>\u0428\u0410\u0413 1. \u041d\u0430\u0447\u0430\u043b\u043e<\/h3>\n<figure class=\"full-width\"><\/figure>\n<div class=\"floating-image\">\n<figure class=\"full-width\"><\/figure>\n<\/div>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameViwModel<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">import SwiftUI  enum Direction {     case up, down, left, right }  class GameViewModel: ObservableObject {     @Published var board: [[Int]]     @Published var gameOver = false      init() {         board = Array(repeating: Array(repeating: 0, count: 4), count: 4)         addNewTile()         addNewTile()     }      func addNewTile() {         var emptyTiles: [(Int, Int)] = []         for row in 0..&lt;4 {             for col in 0..&lt;4 {                 if board[row][col] == 0 {                     emptyTiles.append((row, col))                 }             }         }         if let randomTile = emptyTiles.randomElement() {             board[randomTile.0][randomTile.1] = Bool.random() ? 2 : 4         }     }          func resetGame(_ direction: Direction) {         \/\/ Reset the board to the initial state         board = Array(repeating: Array(repeating: 0, count: 4), count: 4)         gameOver = false         addNewTile()         addNewTile()      }      func move(_ direction: Direction) {         \/\/ Implement the movement logic here         \/\/ This will include merging tiles and updating the board state         \/\/ After moving tiles, call addNewTile() to add a new tile     }      func checkGameOver() {         \/\/ Implement the logic to check if the game is over         \/\/ This will involve checking if there are any valid moves left     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameView<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct GameView: View {     @StateObject private var viewModel = GameViewModel()      var body: some View {         VStack {             Text(\"2048\")                 .font(.largeTitle)                 .padding()                          GridView(board: viewModel.board)                 .padding()                          Button(action: {                 \/\/ Implement restart functionality                 viewModel = GameViewModel()             }) {                 Text(\"Restart\")                     .font(.title)                     .padding()             }         }         .onAppear {             \/\/ Initialize game state         }         .onReceive(NotificationCenter.default.publisher(for:                           UIResponder.keyboardWillShowNotification)) { _ in             \/\/ Handle keyboard events or gestures here         }     } }  struct GridView: View {     let board: [[Int]]      var body: some View {         VStack(spacing: 8) {             ForEach(0..&lt;4) { row in                 HStack(spacing: 8) {                     ForEach(0..&lt;4) { col in                         TileView(value: board[row][col])                     }                 }             }         }     } }  struct TileView: View {     let value: Int      var body: some View {         Text(value == 0 ? \"\" : \"\\(value)\")             .frame(width: 80, height: 80)             .background(Color.gray.opacity(0.4))             .cornerRadius(10)             .font(.title)             .foregroundColor(.black)     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><\/figure>\n<details class=\"spoiler\">\n<summary>\u043a\u043e\u0434 GameView \u0441 \u0436\u0435\u0441\u0442\u043e\u043c DragGesture<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"swift\">struct GameView: View {     @StateObject private var viewModel = GameViewModel()      var body: some View {         VStack {             Text(\"2048\")                 .font(.largeTitle)                 .padding()                          GridView(board: viewModel.board)                 .padding()                 .gesture(                     DragGesture()                         .onEnded { value in                             let horizontalAmount = value.translation.width                             let verticalAmount = value.translation.height                                                          if abs(horizontalAmount) &gt; abs(verticalAmount) {                                 if horizontalAmount &gt; 0 {                                     viewModel.move(.right)                                 } else {                                     viewModel.move(.left)                                 }                             } else {                               <\/code><\/pre>\n<\/div>\n<\/details>\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-437641","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/437641","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=437641"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/437641\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=437641"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=437641"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=437641"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}