{"id":351647,"date":"2024-05-20T21:52:18","date_gmt":"2024-05-20T21:52:18","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=351647"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-20T21:52:18","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=351647","title":{"rendered":"<span>\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u043d\u043e\u0439 \u0438\u0433\u0440\u044b \u043d\u0430 Dart+Flutter<\/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<h2>\u041e\u0431 \u0438\u0433\u0440\u0435<\/h2>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0438\u0433\u0440\u0443 \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0443\u044e &#8212; \u044d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433 \u043a\u0440\u0435\u0441\u0442\u0438\u043a\u043e\u0432-\u043d\u043e\u043b\u0438\u043a\u043e\u0432, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0439. \u041d\u0430 \u044d\u0442\u043e\u0439 \u0433\u0438\u0444\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0430\u043c\u0443 \u0438\u0433\u0440\u0443:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/056\/053\/980\/056053980ca75e5b4c37307d427f59a7.gif\" alt=\"\u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0438\u043b\u0430 \u044d\u0442\u0430 \u0433\u0438\u0444\u043a\u0430\" title=\"\u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0438\u043b\u0430 \u044d\u0442\u0430 \u0433\u0438\u0444\u043a\u0430\" width=\"210\" height=\"305\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/056\/053\/980\/056053980ca75e5b4c37307d427f59a7.gif\"\/><\/p>\n<div><figcaption>\u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0438\u043b\u0430 \u044d\u0442\u0430 \u0433\u0438\u0444\u043a\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0433\u0438\u0444\u043a\u0438, \u044f \u0438 \u0437\u0430\u0445\u043e\u0442\u0435\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435. \u0418\u0433\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u043d\u043e\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u043f\u043e\u0432\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u044f \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u044e \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438 &#8212; \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u0441 \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0441\u0442\u0430\u0442\u044c\u044f, \u0430 \u043d\u0443\u0436\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434, \u0442\u043e \u043e\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a href=\"https:\/\/github.com\/loothood\/ttt_game\/tree\/v1\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a> <\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b dart \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438 flutter+flame \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u041f\u043e\u0447\u0435\u043c\u0443 dart \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435? \u041c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f flutter, \u0430 \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 dart, \u0442\u043e \u0440\u0435\u0448\u0438\u043b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u0442 \u0436\u0435 \u044f\u0437\u044b\u043a \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0448\u0430\u0440\u0438\u043d\u0433\u0430 \u0447\u0430\u0441\u0442\u0435\u0439 \u043a\u043e\u0434\u0430. <\/p>\n<p>\u042f \u0445\u043e\u0447\u0443 \u0447\u0442\u043e\u0431\u044b \u0438\u0433\u0440\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u0435\u0437\u0434\u0435 &#8212; desktop, mobile, web. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0432\u0441\u0435 \u044d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 flutter. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 &#8212; \u0443 \u043c\u0435\u043d\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0435\u0441\u0442\u044c web. \u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u0447\u0435\u0440\u0435\u0437 websocket. <\/p>\n<p>\u0421 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438\u0441\u044c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443.<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c flutter \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<pre><code class=\"bash\">flutter create tttgame<\/code><\/pre>\n<p>\u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 <code>pubspec.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">dependencies:   flutter:     sdk: flutter    logging: ^1.0.2   flame: ^1.8.1   uuid: ^3.0.7   base2e15: ^1.0.0   web_socket_channel: ^2.4.0<\/code><\/pre>\n<p>\u041f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443:<\/p>\n<ul>\n<li>\n<p><code>logging<\/code> &#8212; \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p><code>flame<\/code> &#8212; \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u0432\u0438\u0436\u043e\u043a \u0434\u043b\u044f flutter. \u041f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u043d\u0435\u043c \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/docs.flame-engine.org\/latest\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a><\/p>\n<\/li>\n<li>\n<p><code>uuid<\/code> &#8212;  \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p><code>base2e15<\/code> &#8212; \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c. <\/p>\n<\/li>\n<li>\n<p><code>web_socket_channel<\/code> &#8212; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u0412 dart \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 websocket. <code>dart:io<\/code> &#8212; \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 desktop \u0438 <code>dart:html<\/code> &#8212; \u0434\u043b\u044f web . \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u0430\u0449\u0438\u0442\u044c \u0432 \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u043d\u0430 \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 (websocket \u0432 <code>dart:io<\/code> \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 websocket \u0432 <code>dart:html<\/code>), \u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 <code>dart pub get<\/code> \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u0441\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0438 \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <s>\u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/s> \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<h2>\u0421\u0435\u0440\u0432\u0435\u0440-\u041a\u043b\u0438\u0435\u043d\u0442 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c \u043a\u0430\u043a \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c? \u041a\u0430\u043a \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u043c \u0431\u0443\u0434\u0435\u0442 websocket, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/pub.dev\/packages\/base2e15\" rel=\"noopener noreferrer nofollow\">base2e15<\/a><\/p>\n<p>\u042f \u0432\u0438\u0436\u0443 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0448\u0435\u0439 \u0438\u0433\u0440\u044b \u0442\u0430\u043a: \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0434\u0430\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b. \u041d\u0430 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u044b\u043b\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0433\u0440\u044b. \u041a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u0441\u0432\u043e\u0435\u043c \u0445\u043e\u0434\u0435. \u0418 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 &#8212; \u044d\u0442\u043e\u0442 \u0445\u043e\u0434 \u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d \u0438\u043b\u0438 \u043d\u0435\u0442. \u0418\u0442\u043e\u0433\u043e, \u0443 \u043d\u0430\u0441 \u0442\u0440\u0438 \u0442\u0438\u043f\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0435\u0440\u0435\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>welcome &#8212; \u043a\u043e\u0433\u0434\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043e\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u044d\u0442\u0438\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443.<\/p>\n<\/li>\n<li>\n<p>gameStatus &#8212; \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0448\u043b\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0433\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>move &#8212; \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u043b\u0438\u0435\u043d\u0442 \u0448\u043b\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0441\u0432\u043e\u0435\u043c \u0445\u043e\u0434\u0435 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0448\u043b\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u0445\u043e\u0434\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0427\u0442\u043e \u0436, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>lib<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0443 <code>entity<\/code>, \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 \u0444\u0430\u0439\u043b <code>message.dart<\/code> \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c:<\/p>\n<pre><code class=\"dart\">enum MessageType {   welcome,   gameStatus,   move, }<\/code><\/pre>\n<p>\u0412 \u0442\u043e\u0439 \u0436\u0435 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 <code>enum<\/code>:<\/p>\n<details class=\"spoiler\">\n<summary>player_role.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">enum PlayerRole {   topPlayer,   bottomPlayer,   observer, }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0433\u0440\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u0435\u0440\u0445\u0443 \u0441\u0442\u043e\u043b\u0430, \u0441\u043d\u0438\u0437\u0443 \u0441\u0442\u043e\u043b\u0430 \u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u043c<\/p>\n<details class=\"spoiler\">\n<summary>winner.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">enum Winner {   none,   top,   bottom, }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c, \u0442\u0430\u043a \u0436\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0433\u0440\u043e\u043a \u0441\u0432\u0435\u0440\u0445\u0443 \u0438\u043b\u0438 \u0438\u0433\u0440\u043e\u043a \u0441\u043d\u0438\u0437\u0443<\/p>\n<details class=\"spoiler\">\n<summary>figure_type.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>enum FigureType {   small,   medium,   large,   none, } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0423 \u043d\u0430\u0441 \u0442\u0440\u0438 \u0442\u0438\u043f\u0430 \u0444\u0438\u0433\u0443\u0440: \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f, \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0438\u043b\u0438 \u0441\u0440\u0435\u0434\u043d\u044f\u044f. \u0422\u0430\u043a \u0436\u0435, \u0444\u0438\u0433\u0443\u0440\u044b \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0432 \u044f\u0447\u0435\u0439\u043a\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0434\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c. \u041a\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u0438\u0448\u043b\u043e \u043d\u0435 welcome \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0430 gameStatus? \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043f\u0435\u0440\u0432\u044b\u043c \u043f\u043e\u043b\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c. <\/p>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0432 \u0444\u0430\u0439\u043b <code>message.dart<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>message.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">class Message {   final MessageType type;   final WelcomeMessage? welcomeMessage;   final Move? move;   final GameStatus? gameStatus;    Message(this.type, {this.welcomeMessage, this.move, this.gameStatus});    factory Message.fromJson(Map&lt;String, dynamic> json) {     return Message(       MessageType.values.firstWhere((e) => e.toString() == json['type']),       gameStatus: json.containsKey('gameStatus') ? GameStatus.fromJson(json['gameStatus']) : null,       welcomeMessage:           json.containsKey('welcomeMessage') ? WelcomeMessage.fromJson(json['welcomeMessage']) : null,       move:            json.containsKey('move') ? Move.fromJson(json['move']) : null,     );   }    Map&lt;String, dynamic> toJson() {     final Map&lt;String, dynamic> data = {'type': type.toString()};     if (gameStatus != null) {       data['gameStatus'] = gameStatus!.toJson();     }     if (welcomeMessage != null) {       data['welcomeMessage'] = welcomeMessage!.toJson();     }     if (move != null) {       data['move'] = move!.toJson();     }     return data;   }    String toJsonString() {     final jsonString = jsonEncode(toJson());     final base2e15String = Base2e15.encode(jsonString.codeUnits);     return base2e15String;   }    factory Message.fromJsonString(String jsonString) {     final base2e15Bytes = Base2e15.decode(jsonString);     final base2e15String = String.fromCharCodes(base2e15Bytes);     final jsonData = jsonDecode(base2e15String);     return Message.fromJson(jsonData);   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c handle \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435. \u041d\u043e \u0438 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043f\u0435\u0440\u0435\u0441\u043b\u0430\u043b\u0438. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0433\u0443\u0440\u0443 <code>dart<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442 \u043f\u043e\u0447\u0435\u043c\u0443 \u043c\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439, \u0441 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435\u043c \u0432\u044b\u0441\u043b\u0443\u0448\u0430\u044e.<\/p>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><code>final MessageType type;<\/code> &#8212; \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u043f\u0440\u0438\u0448\u043b\u043e.<\/p>\n<\/li>\n<li>\n<p> <code>final WelcomeMessage? welcomeMessage;<br \/> final Move? move;<br \/> final GameStatus? gameStatus;<\/code><\/p>\n<p>\u042d\u0442\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430. \u041e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c null. \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435: <code>Message(this.type, {this.welcomeMessage, this.move, this.gameStatus});<\/code> &#8212; \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0447\u0442\u043e \u044d\u0442\u0438 \u043f\u043e\u043b\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u043c\u0438. <\/p>\n<\/li>\n<li>\n<p><code>factory Message.fromJson<\/code>  &#8212; \u0442\u0443\u0442 \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e. \u0415\u0441\u043b\u0438 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438 \u0431\u044b\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 <code>MessageType<\/code>, \u0442\u043e \u043c\u044b \u0435\u0433\u043e \u043f\u0430\u0440\u0441\u0438\u043c \u0438\u0437 json \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 <code>toJson()<\/code>  &#8212; \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u044f \u043d\u0435 \u043f\u0443\u0441\u0442\u044b\u0435, \u0442\u043e \u043c\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0432 json.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 <code>String toJsonString()<\/code>\u0438 <code>factory Message.fromJsonString(String jsonString)<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\\\u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 <code>base2e15<\/code> \u0438\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0430\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u044b <code>WelcomeMessage<\/code>, <code>Move<\/code>, <code>GameStatus<\/code> :<\/p>\n<details class=\"spoiler\">\n<summary>welcome_message.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'player_role.dart';  class WelcomeMessage {   WelcomeMessage(this.clientId, this.canPlay, this.playerRole);   final String clientId;   final bool canPlay;   final PlayerRole playerRole;    factory WelcomeMessage.fromJson(Map&lt;String, dynamic> json) {     return WelcomeMessage(       json['clientId'],       json['canPlay'],       PlayerRole.values.byName(json['playerRole']),     );   }    Map&lt;String, dynamic> toJson() => {         'clientId': clientId,         'canPlay': canPlay,         'playerRole': playerRole.name,       }; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>move.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'figure_type.dart';  class Move {   Move(this.clientId, this.sourceCellId, this.targetCellId, this.figureType,       {this.canPut});   String clientId;   int sourceCellId;   int targetCellId;   FigureType figureType;   bool? canPut;    factory Move.fromJson(Map&lt;String, dynamic> json) => Move(         json['clientId'],         json['sourceCellId'],         json['targetCellId'],         FigureType.values.byName(json['figureType']),         canPut: json.containsKey('canPut') ? json['canPut'] : null,       );    Map&lt;String, dynamic> toJson() {     final Map&lt;String, dynamic> data = {       'clientId': clientId,       'sourceCellId': sourceCellId,       'targetCellId': targetCellId,       'figureType': figureType.name,     };     if (canPut != null) {       data['canPut'] = canPut;     }     return data;   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>game_status.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'board.dart';  class GameStatus {   GameStatus(this.board, {this.winnerId});   Board board;   String? winnerId;    factory GameStatus.fromJson(Map&lt;String, dynamic> json) {     return GameStatus(       Board.fromJson(json['board']),       winnerId: json.containsKey('winnerId') ? json['winnerId'] : null,     );   }    Map&lt;String, dynamic> toJson() {     final Map&lt;String, dynamic> data = {       'board': board.toJson(),     };     if (winnerId != null) {       data['winnerId'] = winnerId;     }     return data;   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u0430\u043a \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>GameStatus<\/code> \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 Board. \u041c\u044b \u043a \u043d\u0435\u043c\u0443 \u0441\u043a\u043e\u0440\u043e \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e. \u0412\u0441\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u0445\u043e\u0436\u0438. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445 <code>fromJson<\/code> \u0438 <code>toJson<\/code>  \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u043f\u043e\u043b\u0435\u0439 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438\u0437\\\u0432 json \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0441\u0435\u0442\u0438.<\/p>\n<p>\u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u043f\u043e \u043f\u043e\u043b\u044f\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><code>class WelcomeMessage<\/code>:<\/p>\n<ul>\n<li>\n<p><code>final String clientId<\/code> &#8212; \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0435\u0433\u043e \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440<\/p>\n<\/li>\n<li>\n<p><code>final bool canPlay<\/code> &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u043d\u0430\u0435\u0442 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e. \u0418 \u0435\u0441\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0434\u0432\u0443\u0445, \u0442\u043e \u0438\u0433\u0440\u043e\u043a \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u0433\u0440\u0430\u0442\u044c. <\/p>\n<\/li>\n<li>\n<p><code>final PlayerRole playerRole;<\/code> &#8212; \u0437\u0430 \u0441\u0442\u043e\u043b\u043e\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u043c\u0435\u0441\u0442\u0430 &#8212; \u0432\u0435\u0440\u0445\u043d\u0438\u0439 \u0438\u0433\u0440\u043e\u043a \u0438 \u043d\u0438\u0436\u043d\u0438\u0439. \u0422\u0430\u043a \u0436\u0435, \u0435\u0441\u0442\u044c \u0440\u043e\u043b\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u0444\u0438\u0433\u0443\u0440\u044b, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0437\u0430 \u0438\u0433\u0440\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>class Move<\/code>:<\/p>\n<ul>\n<li>\n<p>\u00a0<code>String clientId<\/code> &#8212; \u0442\u0430\u043a \u043a\u043b\u0438\u0435\u043d\u0442 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0447\u0442\u043e \u0441\u0445\u043e\u0434\u0438\u043b \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d<\/p>\n<\/li>\n<li>\n<p><code>int sourceCellId<\/code> &#8212; \u0438\u0437 \u043a\u0430\u043a\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u0431\u044b\u043b\u0430 \u0432\u0437\u044f\u0442\u0430 \u0444\u0438\u0433\u0443\u0440\u0430<\/p>\n<\/li>\n<li>\n<p><code>int targetCellId<\/code> &#8212; \u0432 \u043a\u0430\u043a\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 \u044d\u0442\u0443 \u0444\u0438\u0433\u0443\u0440\u0443 \u0445\u043e\u0447\u0435\u0442 \u0438\u0433\u0440\u043e\u043a \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c<\/p>\n<\/li>\n<li>\n<p><code>FigureType figureType<\/code>&#8212; \u0442\u0438\u043f \u0444\u0438\u0433\u0443\u0440\u044b (\u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f, \u0441\u0440\u0435\u0434\u043d\u044f\u044f, \u0431\u043e\u043b\u044c\u0448\u0430\u044f)<\/p>\n<\/li>\n<li>\n<p><code>bool? canPut<\/code>&#8212; \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442. \u0415\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438 true \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0445\u043e\u0434 \u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d \u0438 false \u0435\u0441\u043b\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>class GameStatus<\/code>:<\/p>\n<ul>\n<li>\n<p><code>String? winnerId<\/code> &#8212; \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u0438 \u0440\u0430\u0432\u043d\u043e <code>null<\/code> \u043f\u043e\u043a\u0430 \u0432 \u0438\u0433\u0440\u0435 \u043d\u0435\u0442 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044f. \u0415\u0441\u043b\u0438 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0441\u044f, \u0442\u043e \u0442\u0443\u0442 \u0431\u0443\u0434\u0435\u0442 <code>clientId<\/code> \u043f\u043e\u0431\u0435\u0434\u0438\u0432\u0448\u0435\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430<\/p>\n<\/li>\n<li>\n<p><code>Board board<\/code>&#8212; \u0442\u0443\u0442 \u0436\u0438\u0432\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. <\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u0444\u0438\u0433\u0443\u0440 &#8212; \u043e\u043d \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442 \u0438 \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>figure.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'figure_type.dart';  class Figure {   const Figure(this.figureType, this.color, this.cellId);    final FigureType figureType;   final int color;   final int cellId;    factory Figure.fromJson(Map&lt;String, dynamic> json) {     return Figure(       FigureType.values.byName(json['figureType']),       json['color'],       json['cellId'],     );   }    Map&lt;String, dynamic> toJson() => {         'figureType': figureType.name,         'color': color,         'cellId': cellId,       }; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b, \u043f\u043e\u0442\u043e\u043c\u0443 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u043f\u0430\u043f\u043a\u0435 <code>lib<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0443 <code>common<\/code> \u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u0435\u0435 \u0444\u0430\u0439\u043b <code>constants.dart<\/code> :<\/p>\n<details class=\"spoiler\">\n<summary>constants.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import '..\/entity\/figure.dart'; import '..\/entity\/figure_type.dart';  abstract class Constants {   static const int player1Color = 1;   static const int player2Color = 2;   static const int fakeCellId = 404;   static const int noColor = 0;      static const Figure noneFigure = Figure(FigureType.none, noColor, fakeCellId);   static const List&lt;List&lt;int>> winnigCombinations = &lt;List&lt;int>>[     &lt;int>[3, 4, 5],     &lt;int>[6, 7, 8],     &lt;int>[9, 10, 11],     &lt;int>[3, 7, 11],     &lt;int>[5, 7, 9],     &lt;int>[3, 6, 9],     &lt;int>[4, 7, 10],     &lt;int>[5, 8, 11],   ];   static const int winningCount = 3;   static const int port = 8080;   static const int maxAttempts = 5;   static const String host = 'localhost';   static const Duration reconnectDelay = Duration(seconds: 5);   static const broadcastInterval = Duration(milliseconds: 100); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u0443 \u043d\u0430\u0441 \u0441\u0435\u0440\u0432\u0435\u0440 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0438 \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0446\u0432\u0435\u0442\u0430 \u0438\u0437 <code>materials.dart<\/code> \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b, \u0442\u043e \u043c\u044b \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u043c \u0438\u0445 \u0446\u0438\u0444\u0440\u0430\u043c\u0438. \u0422\u0430\u043a \u0436\u0435, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u044b <code>noneFigure<\/code> \u0438 <code>winningCombinations<\/code>  \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0412\u043e\u0442 \u043c\u044b \u0438 \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u0438\u0433\u0440\u044b \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>entity<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>board.dart<\/code> \u0438 \u0432\u0437\u0433\u043b\u044f\u043d\u0435\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>board.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import '..\/common\/constants.dart'; import 'figure.dart'; import 'figure_type.dart'; import 'winner.dart';  class Board {   List&lt;Figure> figures;    Board(this.figures);    factory Board.fromJson(Map&lt;String, dynamic> json) {     final List&lt;dynamic> figuresJson = json['figures'];     final figures =         figuresJson.map((figureJson) => Figure.fromJson(figureJson)).toList();     return Board(figures);   }    Map&lt;String, dynamic> toJson() => {         'figures': figures.map((figure) => figure.toJson()).toList(),       };    void startnewGame() {     figures.clear();     figures.add(const Figure(FigureType.small, Constants.player1Color, 0));     figures.add(const Figure(FigureType.small, Constants.player1Color, 0));      figures.add(const Figure(FigureType.medium, Constants.player1Color, 1));     figures.add(const Figure(FigureType.medium, Constants.player1Color, 1));      figures.add(const Figure(FigureType.large, Constants.player1Color, 2));     figures.add(const Figure(FigureType.large, Constants.player1Color, 2));      figures.add(const Figure(FigureType.small, Constants.player2Color, 12));     figures.add(const Figure(FigureType.small, Constants.player2Color, 12));      figures.add(const Figure(FigureType.medium, Constants.player2Color, 13));     figures.add(const Figure(FigureType.medium, Constants.player2Color, 13));      figures.add(const Figure(FigureType.large, Constants.player2Color, 14));     figures.add(const Figure(FigureType.large, Constants.player2Color, 14));   }    void removeFigureFromCell(int cellId) {     final int index = figures         .indexWhere((Figure figureServer) => figureServer.cellId == cellId);     if (index != -1) {       figures.removeAt(index);     }   }    bool canPutFigure(int cellId, FigureType otherFigureType) {     final Figure figureServer = figures.lastWhere(         (Figure figureServer) => figureServer.cellId == cellId,         orElse: () => Constants.noneFigure);     if (figureServer.figureType == FigureType.none) {       return true;     } else if (figureServer.figureType == FigureType.large) {       return false;     } else {       switch (otherFigureType) {         case FigureType.small:           return false;         case FigureType.medium:           if (figureServer.figureType == FigureType.small) {             return true;           } else {             return false;           }         case FigureType.large:           if (figureServer.figureType == FigureType.small ||               figureServer.figureType == FigureType.medium) {             return true;           } else {             return false;           }         case FigureType.none:           return true;       }     }   }    void putFigure(Figure figure) =>       figures.add(Figure(figure.figureType, figure.color, figure.cellId));    Winner checkWinner() {     if (playerWin(Constants.player1Color)) {       return Winner.top;     } else if (playerWin(Constants.player2Color)) {       return Winner.bottom;     }     return Winner.none;   }    bool playerWin(int playerColor) {     final List&lt;int> playerCells = &lt;int>[];     for (final Figure pFigure in figures) {       final Figure lastFigure = figures           .where((Figure element) => element.cellId == pFigure.cellId)           .last;       if (lastFigure.color == playerColor) {         playerCells.add(pFigure.cellId);       }     }     for (final List&lt;int> wins in Constants.winnigCombinations) {       int matchCount = 0;       for (final int w in wins) {         if (playerCells.contains(w)) {           matchCount++;         }       }       if (matchCount == Constants.winningCount) {         return true;       }     }     return false;   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0435\u0441\u0442\u044c \u0443 \u043a\u043b\u0430\u0441\u0441\u0430 \u044d\u0442\u043e <code>List&lt;Figure> figures<\/code>  &#8212; \u0441\u043f\u0438\u0441\u043e\u043a \u0444\u0438\u0433\u0443\u0440 \u043d\u0430 \u0438\u0433\u0440\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435. <\/p>\n<p>\u0427\u0443\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043f\u0440\u043e \u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435. \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e \u043d\u0430 \u0433\u0438\u0444\u043a\u0435 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435, \u0432\u0441\u0435 \u043f\u043e\u043b\u0435 &#8212; \u044d\u0442\u043e 15 \u044f\u0447\u0435\u0435\u043a. \u0412 \u043d\u0430\u0448\u0435\u0439 \u0438\u0433\u0440\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0442\u0430\u043a:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0fd\/e1f\/21e\/0fde1f21e129308dcb38a95e53c0a61e.png\" alt=\"\u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435\" title=\"\u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435\" width=\"385\" height=\"610\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0fd\/e1f\/21e\/0fde1f21e129308dcb38a95e53c0a61e.png\"\/><\/p>\n<div><figcaption>\u0438\u0433\u0440\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u044f\u0447\u0435\u0439\u043a\u0430\u0445 0,1,2,12,13,14 \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0444\u0438\u0433\u0443\u0440\u044b \u0438\u0433\u0440\u043e\u043a\u043e\u0432 (\u043f\u043e \u0434\u0432\u0435 \u0448\u0442\u0443\u043a\u0438 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u043e\u043b\u0435), \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u044f\u0447\u0435\u0439\u043a\u0438 \u043f\u0443\u0441\u0442\u044b\u0435. \u0418\u043c\u0435\u043d\u043d\u043e \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044f\u0441\u044c \u043d\u0430 \u0442\u0430\u043a\u043e\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>removeFigureFromCell<\/code>\u0438 <code>startnewGame<\/code>,<code>putFigure<\/code>. \u0424\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0438 \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0438  \u0438\u0445 \u043b\u043e\u0433\u0438\u043a\u0438. <\/p>\n<p>\u041d\u0430 \u0432\u0445\u043e\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>canPutFigure<\/code> \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u044f\u0447\u0435\u0439\u043a\u0430 \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0438\u0433\u0440\u043e\u043a \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0444\u0438\u0433\u0443\u0440\u0443 \u0438 \u0442\u0438\u043f \u0444\u0438\u0433\u0443\u0440\u044b \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c. \u041c\u044b \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0441\u0442\u044c \u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0444\u0438\u0433\u0443\u0440\u044b \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0435, \u0430 \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c, \u0442\u043e \u043a\u0430\u043a\u043e\u0433\u043e \u043e\u043d\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \u0415\u0441\u043b\u0438 \u0444\u0438\u0433\u0443\u0440\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u044d\u0442\u0443 \u044f\u0447\u0435\u0439\u043a\u0443 \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440, \u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u044d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u043c.<\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 <code>checkWinner<\/code> \u0438 <code>playerWin<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u0435\u0441\u0442\u044c \u043b\u0438 \u0443 \u043d\u0430\u0441 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c \u043f\u043e\u0441\u043b\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u0445\u043e\u0434\u0430. \u041c\u044b \u0431\u0435\u0440\u0435\u043c <code>winnigCombinations<\/code> \u0438\u0437 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442, \u0433\u0434\u0435 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u044b \u0432\u0441\u0435 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u044f\u0447\u0435\u0435\u043a \u0434\u043b\u044f \u043f\u043e\u0431\u0435\u0434\u044b \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0444\u0438\u0433\u0443\u0440 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. \u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u0441\u043e\u0432\u043f\u0430\u043b\u0438, \u0442\u043e \u0438\u0433\u0440\u043e\u043a \u043f\u043e\u0431\u0435\u0434\u0438\u043b.<\/p>\n<h2>\u0421\u0435\u0440\u0432\u0435\u0440<\/h2>\n<p>\u0412\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u041e\u043d \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0439. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <code>dart:io<\/code>  \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438.<\/p>\n<p>\u0418\u0434\u0435\u043c \u0432 \u043f\u0430\u043f\u043a\u0443 <code>lib<\/code>, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043f\u0430\u043f\u043a\u0443 <code>server<\/code> \u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0435 \u0444\u0430\u0439\u043b <code>server.dart<\/code> .<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0441\u0435\u0440\u0432\u0435\u0440\u0430:<\/p>\n<details class=\"spoiler\">\n<summary>server.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'dart:async'; import 'dart:io'; import 'package:logging\/logging.dart'; import 'package:uuid\/uuid.dart'; import '..\/common\/constants.dart'; import '..\/entity\/message.dart'; import '..\/entity\/player_role.dart'; import '..\/entity\/welcome_message.dart'; import '..\/server\/game_state.dart';  class ServerManager {   final Logger _log = Logger('Server');   final Map&lt;String, WebSocket> connectedClients = {};   bool gameStated = false;   GameState gameState = GameState();    void init() async {     final server =         await HttpServer.bind(InternetAddress.loopbackIPv4, Constants.port);     _log.info(         'WebSocket started ws:\/\/${server.address.address}:${server.port}\/');      await for (HttpRequest request in server) {       if (WebSocketTransformer.isUpgradeRequest(request)) {         WebSocketTransformer.upgrade(request).then((webSocket) {           handleNewConnection(webSocket);         });          broadcast();       } else {         request.response.write('Pizza delivering');         await request.response.close();       }     }   }    void handleNewConnection(WebSocket webSocket) {     final clientId = const Uuid().v4();     _log.info('A new client connected: $clientId.');      connectedClients[clientId] = webSocket;     bool canPlay = false;     PlayerRole playerRole = PlayerRole.observer;     if (connectedClients.length &lt;= 2) {       canPlay = true;       if (connectedClients.length == 1) {         gameState.topPlayerId = clientId;         playerRole = PlayerRole.topPlayer;       } else if (connectedClients.length == 2) {         gameState.bottomPlayerId = clientId;         playerRole = PlayerRole.bottomPlayer;       }     }      final welcomeMessage = Message(MessageType.welcome,         welcomeMessage: WelcomeMessage(clientId, canPlay, playerRole));     final messageString = welcomeMessage.toJsonString();     webSocket.add(messageString);     if (connectedClients.length > 1) {       if (!gameStated) {         _log.info(             'A new game starting for clients: ${connectedClients.keys.toString()}');         gameState.gameStatus.board.startnewGame();         gameStated = true;       }     }     handleMessages(webSocket, clientId);   }    void handleMessages(WebSocket webSocket, String clientId) {     webSocket.listen((data) {       final message = Message.fromJsonString(data);       if (message.type == MessageType.move) {         final move = message.move;         gameState.moveFigure(move!);       }     }, onError: (error) {       _log.shout('Error connection for client $clientId: $error');       connectedClients.remove(clientId);     }, onDone: () {       _log.warning('Connection for client $clientId closed');       connectedClients.remove(clientId);     });   }    void broadcast() {     Timer.periodic(Constants.broadcastInterval, (timer) {       final message =           Message(MessageType.gameStatus, gameStatus: gameState.gameStatus);       final messageString = message.toJsonString();       connectedClients.forEach((clientId, webSocket) {         webSocket.add(messageString);       });     });   } }  void main() async {   Logger.root.onRecord.listen((record) {     \/\/ ignore: avoid_print     print('${record.level.name}: ${record.time}: '         '${record.loggerName}: '         '${record.message}');   });   ServerManager server = ServerManager();   server.init(); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443:<\/p>\n<ul>\n<li>\n<p><code>final Logger _log = Logger('Server');<\/code>  &#8212; \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c \u043b\u043e\u0433\u0433\u0435\u0440 \u0447\u0442\u043e\u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c. <\/p>\n<\/li>\n<li>\n<p><code>final Map&lt;String, WebSocket> connectedClients = {};<\/code>  &#8212; \u0442\u0443\u0442 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p><code>bool gameStated = false;<\/code>  &#8212; \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u043b\u044f \u0438\u0433\u0440\u044b \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e 2 \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430, \u0430 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0443 \u043d\u0430\u0441 0, \u0442\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u0433\u0440\u0430 \u043d\u0435 \u043d\u0430\u0447\u0430\u043b\u0430\u0441\u044c.<\/p>\n<\/li>\n<li>\n<p><code>GameState gameState = GameState();<\/code>  &#8212; \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0433\u0440\u044b \u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>init()<\/code> \u043c\u044b \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u0435\u043c websocket \u0441\u0435\u0440\u0432\u0435\u0440. \u0415\u0441\u043b\u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0438\u0448\u0435\u043b \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 http, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u043e\u0442\u0432\u0435\u0442. \u0415\u0441\u043b\u0438 \u0436\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u044b\u043b \u043a websocket, \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u043e\u0432\u044b\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>handleNewConnection<\/code><\/p>\n<\/li>\n<li>\n<p><code>handleNewConnection<\/code> &#8212; \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430 \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e, \u0432\u044b\u0434\u0430\u0435\u043c \u0435\u043c\u0443 \u0440\u043e\u043b\u044c \u043b\u0438\u0431\u043e \u0437\u0430 \u0438\u0433\u0440\u043e\u0432\u044b\u043c \u0441\u0442\u043e\u043b\u043e\u043c, \u043b\u0438\u0431\u043e \u0440\u043e\u043b\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f. \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0442\u0438\u043f\u0430 <code>WelcomeMessage<\/code> \u0438 \u0448\u043b\u0435\u043c \u0435\u0433\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0443. \u0412 \u043a\u043e\u043d\u0446\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>handleMessages<\/code> \u0447\u0442\u043e\u0431\u044b \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u043a\u0430\u043d\u0430\u043b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c.<\/p>\n<\/li>\n<li>\n<p><code>handleMessages<\/code> &#8212; \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043c\u044b \u043e\u0436\u0438\u0434\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u0430 move. \u0412\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c. \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>gameState.moveFigure(move!) <\/code>&#8212; \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0447\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435.<\/p>\n<\/li>\n<li>\n<p><code>broadcast<\/code> &#8212; \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0433\u0440\u044b \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u044b. \u041a\u0430\u0436\u0434\u044b\u0435 100 \u043c\u0438\u043b\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u0430 <code>MessageType.gameStatus<\/code><\/p>\n<\/li>\n<\/ul>\n<p>\u0427\u0442\u043e \u0436, \u0434\u043b\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043a\u043b\u0430\u0441\u0441. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>server<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b <code>game_state.dart<\/code> \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>game_state.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'package:logging\/logging.dart';  import '..\/entity\/board.dart'; import '..\/entity\/figure.dart'; import '..\/entity\/figure_type.dart'; import '..\/entity\/game_status.dart'; import '..\/entity\/move.dart'; import '..\/entity\/winner.dart'; import '..\/common\/constants.dart';  class GameState {   final Logger _log = Logger('Server');   late String? topPlayerId;   late String? bottomPlayerId;   Winner winner = Winner.none;   bool bottomPlayerTurn = false;   GameStatus gameStatus = GameStatus(Board(&lt;Figure>[]));    Move moveFigure(Move move) {     final FigureType figureType =         FigureType.values.firstWhere((FigureType e) => e == move.figureType);     if (move.clientId == topPlayerId &amp;&amp; !bottomPlayerTurn ||         move.clientId == bottomPlayerId &amp;&amp; bottomPlayerTurn) {       bool canPut =           gameStatus.board.canPutFigure(move.targetCellId, figureType);       if (canPut) {         int color = Constants.player1Color;         bottomPlayerTurn = true;         if (move.clientId == bottomPlayerId) {           color = Constants.player2Color;           bottomPlayerTurn = false;         }         gameStatus.board             .putFigure(Figure(figureType, color, move.targetCellId));         gameStatus.board.removeFigureFromCell(move.sourceCellId);         winner = gameStatus.board.checkWinner();         if (winner == Winner.top) {           _log.info('Player $topPlayerId win');           gameStatus.winnerId = topPlayerId;         } else if (winner == Winner.bottom) {           _log.info('Player $bottomPlayerId win');           gameStatus.winnerId = bottomPlayerId;         }         move.canPut = true;       } else {         move.canPut = false;       }     }     return move;   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u0433\u0440\u044b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0422\u0443\u0442 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0438 \u043e\u0431\u0430 \u0438\u0433\u0440\u043e\u043a\u0430 (<code>topPlayerId<\/code>, <code>bottomPlayerId<\/code>) \u0438 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c (<code>winner<\/code>) \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0445\u043e\u0434\u0430 (<code>bottomPlayerTurn<\/code>) \u0438 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0433\u0440\u044b (<code>gameStatus<\/code>). \u0412 \u043a\u043b\u0430\u0441\u0441\u0435 \u0435\u0441\u0442\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f &#8212; \u043e\u043d\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0438\u043b\u0438 \u043d\u0435 \u0434\u0435\u043b\u0430\u0435\u0442 \u0445\u043e\u0434. \u041b\u043e\u0433\u0438\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0430\u043a\u043e\u0432\u0430: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0435\u0439 \u0445\u043e\u0434 \u0438 \u043c\u043e\u0436\u0435\u0442 \u043b\u0438 \u0438\u0433\u0440\u043e\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0445\u043e\u0434. \u0414\u0430\u043b\u0435\u0435 \u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0444\u0438\u0433\u0443\u0440\u0443 \u043d\u0430 \u0442\u0443 \u043a\u043b\u0435\u0442\u043a\u0443 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0445\u043e\u0447\u0435\u0442 \u0438\u0433\u0440\u043e\u043a. \u0415\u0441\u043b\u0438 \u0434\u0430, \u0442\u043e \u043b\u043e\u0436\u0435\u043c \u0444\u0438\u0433\u0443\u0440\u0443, \u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0444\u0438\u0433\u0443\u0440\u0443 \u0438\u0437 \u044f\u0447\u0435\u0439\u043a\u0438 \u043e\u0442\u043a\u0443\u0434\u0430 \u044d\u0442\u0443 \u0444\u0438\u0433\u0443\u0440\u0443 \u0432\u0437\u044f\u043b\u0438 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0432\u044b\u0438\u0433\u0440\u0430\u043b \u043b\u0438 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0438\u0433\u0440\u043e\u043a \u043f\u043e\u0441\u043b\u0435 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0433\u043e \u0445\u043e\u0434\u0430. \u0412 \u0438\u0442\u043e\u0433\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 <code>Move<\/code> \u0441 \u043e\u0442\u0432\u0435\u0442\u043e\u043c \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430 &#8212; \u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d \u043b\u0438 \u0445\u043e\u0434 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0445\u043e\u0447\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0433\u0440\u043e\u043a.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440. \u041f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u0443\u044e \u043f\u0430\u043f\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u043d\u0430\u043f\u0438\u0448\u0438\u0442\u0435 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438:<\/p>\n<pre><code class=\"bash\">dart .\\lib\\server\\server.dart<\/code><\/pre>\n<p>\u041c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u0430\u043f\u0443\u0449\u0435\u043d:<\/p>\n<pre><code>INFO: 2023-08-08 23:34:56.358943: Server: WebSocket started ws:\/\/127.0.0.1:8080\/<\/code><\/pre>\n<p>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>curl<\/code> \u0438\u043b\u0438 <code>telnet<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0447\u0442\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442. <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0432\u0441\u0435. \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435. \u041a\u043e\u0434 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a href=\"https:\/\/github.com\/loothood\/ttt_game\/tree\/v1\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043d\u0430\u0448\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c.<\/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\/753402\/\"> https:\/\/habr.com\/ru\/articles\/753402\/<\/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<h2>\u041e\u0431 \u0438\u0433\u0440\u0435<\/h2>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442, \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0438\u0433\u0440\u0443 \u0431\u0443\u0434\u0435\u043c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0443\u044e &#8212; \u044d\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433 \u043a\u0440\u0435\u0441\u0442\u0438\u043a\u043e\u0432-\u043d\u043e\u043b\u0438\u043a\u043e\u0432, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u0439. \u041d\u0430 \u044d\u0442\u043e\u0439 \u0433\u0438\u0444\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0430\u043c\u0443 \u0438\u0433\u0440\u0443:<\/p>\n<figure class=\"\">\n<div><figcaption>\u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0438\u043b\u0430 \u044d\u0442\u0430 \u0433\u0438\u0444\u043a\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0433\u0438\u0444\u043a\u0438, \u044f \u0438 \u0437\u0430\u0445\u043e\u0442\u0435\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435. \u0418\u0433\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043b\u0435\u0435\u0440\u043d\u043e\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u043f\u043e\u0432\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u044f \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u044e \u043d\u0430 \u0434\u0432\u0435 \u0447\u0430\u0441\u0442\u0438 &#8212; \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u0441 \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0441\u0442\u0430\u0442\u044c\u044f, \u0430 \u043d\u0443\u0436\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434, \u0442\u043e \u043e\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d <a href=\"https:\/\/github.com\/loothood\/ttt_game\/tree\/v1\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a> <\/p>\n<p>\u042f \u0432\u044b\u0431\u0440\u0430\u043b dart \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438 flutter+flame \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u041f\u043e\u0447\u0435\u043c\u0443 dart \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435? \u041c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f flutter, \u0430 \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 dart, \u0442\u043e \u0440\u0435\u0448\u0438\u043b \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u0442 \u0436\u0435 \u044f\u0437\u044b\u043a \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0448\u0430\u0440\u0438\u043d\u0433\u0430 \u0447\u0430\u0441\u0442\u0435\u0439 \u043a\u043e\u0434\u0430. <\/p>\n<p>\u042f \u0445\u043e\u0447\u0443 \u0447\u0442\u043e\u0431\u044b \u0438\u0433\u0440\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u0435\u0437\u0434\u0435 &#8212; desktop, mobile, web. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0432\u0441\u0435 \u044d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 flutter. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 &#8212; \u0443 \u043c\u0435\u043d\u044f \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0435\u0441\u0442\u044c web. \u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u0447\u0435\u0440\u0435\u0437 websocket. <\/p>\n<p>\u0421 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438\u0441\u044c, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0443.<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c flutter \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<pre><code class=\"bash\">flutter create tttgame<\/code><\/pre>\n<p>\u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u043f\u0440\u043e\u043f\u0438\u0448\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 <code>pubspec.yaml<\/code>:<\/p>\n<pre><code class=\"yaml\">dependencies:   flutter:     sdk: flutter    logging: ^1.0.2   flame: ^1.8.1   uuid: ^3.0.7   base2e15: ^1.0.0   web_socket_channel: ^2.4.0<\/code><\/pre>\n<p>\u041f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443:<\/p>\n<ul>\n<li>\n<p><code>logging<\/code> &#8212; \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p><code>flame<\/code> &#8212; \u0438\u0433\u0440\u043e\u0432\u043e\u0439 \u0434\u0432\u0438\u0436\u043e\u043a \u0434\u043b\u044f flutter. \u041f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e \u043d\u0435\u043c \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/docs.flame-engine.org\/latest\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0443\u0442<\/a><\/p>\n<\/li>\n<li>\n<p><code>uuid<\/code> &#8212;  \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p><code>base2e15<\/code> &#8212; \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0443\u043c\u0435\u043d\u044c\u0448\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c. <\/p>\n<\/li>\n<li>\n<p><code>web_socket_channel<\/code> &#8212; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435. \u0412 dart \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432 \u043a \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 websocket. <code>dart:io<\/code> &#8212; \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0432 desktop \u0438 <code>dart:html<\/code> &#8212; \u0434\u043b\u044f web . \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0442\u0430\u0449\u0438\u0442\u044c \u0432 \u043a\u043e\u0434 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u043d\u0430 \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 (websocket \u0432 <code>dart:io<\/code> \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 websocket \u0432 <code>dart:html<\/code>), \u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 <code>dart pub get<\/code> \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0442\u044f\u043d\u0443\u0442\u044c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432\u0441\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u0438 \u043c\u044b \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <s>\u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/s> \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0430.<\/p>\n<h2>\u0421\u0435\u0440\u0432\u0435\u0440-\u041a\u043b\u0438\u0435\u043d\u0442 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u044f<\/h2>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0443\u043c\u0430\u0435\u043c \u043a\u0430\u043a \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u043c? \u041a\u0430\u043a \u0443\u0436\u0435 \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u043e\u043c \u0431\u0443\u0434\u0435\u0442 websocket, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/pub.dev\/packages\/base2e15\" rel=\"noopener noreferrer nofollow\">base2e15<\/a><\/p>\n<p>\u042f \u0432\u0438\u0436\u0443 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0448\u0435\u0439 \u0438\u0433\u0440\u044b \u0442\u0430\u043a: \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443, \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044b\u0434\u0430\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b. \u041d\u0430 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u044b\u043b\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0433\u0440\u044b. \u041a\u043b\u0438\u0435\u043d\u0442 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u0441\u0432\u043e\u0435\u043c \u0445\u043e\u0434\u0435. \u0418 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 &#8212; \u044d\u0442\u043e\u0442 \u0445\u043e\u0434 \u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d \u0438\u043b\u0438 \u043d\u0435\u0442. \u0418\u0442\u043e\u0433\u043e, \u0443 \u043d\u0430\u0441 \u0442\u0440\u0438 \u0442\u0438\u043f\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0435\u0440\u0435\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043a \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>welcome &#8212; \u043a\u043e\u0433\u0434\u0430 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430, \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043e\u0441\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u044d\u0442\u0438\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443.<\/p>\n<\/li>\n<li>\n<p>gameStatus &#8212; \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b \u0448\u043b\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u0442\u0430\u0442\u0443\u0441 \u0438\u0433\u0440\u044b.<\/p>\n<\/li>\n<li>\n<p>move &#8212; \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u043b\u0438\u0435\u043d\u0442 \u0448\u043b\u0435\u0442 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0441\u0432\u043e\u0435\u043c \u0445\u043e\u0434\u0435 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0448\u043b\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u044d\u0442\u043e\u0433\u043e \u0445\u043e\u0434\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u0427\u0442\u043e \u0436, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432 \u043f\u0430\u043f\u043a\u0435 <code>lib<\/code> \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0443 <code>entity<\/code>, \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0439 \u043f\u0430\u043f\u043a\u0438 \u0444\u0430\u0439\u043b <code>message.dart<\/code> \u0438 \u043d\u0430\u043f\u0438\u0448\u0435\u043c:<\/p>\n<pre><code class=\"dart\">enum MessageType {   welcome,   gameStatus,   move, }<\/code><\/pre>\n<p>\u0412 \u0442\u043e\u0439 \u0436\u0435 \u043f\u0430\u043f\u043a\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 <code>enum<\/code>:<\/p>\n<details class=\"spoiler\">\n<summary>player_role.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">enum PlayerRole {   topPlayer,   bottomPlayer,   observer, }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0433\u0440\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u0435\u0440\u0445\u0443 \u0441\u0442\u043e\u043b\u0430, \u0441\u043d\u0438\u0437\u0443 \u0441\u0442\u043e\u043b\u0430 \u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u043c<\/p>\n<details class=\"spoiler\">\n<summary>winner.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">enum Winner {   none,   top,   bottom, }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044f \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c, \u0442\u0430\u043a \u0436\u0435 \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0433\u0440\u043e\u043a \u0441\u0432\u0435\u0440\u0445\u0443 \u0438\u043b\u0438 \u0438\u0433\u0440\u043e\u043a \u0441\u043d\u0438\u0437\u0443<\/p>\n<details class=\"spoiler\">\n<summary>figure_type.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>enum FigureType {   small,   medium,   large,   none, } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0423 \u043d\u0430\u0441 \u0442\u0440\u0438 \u0442\u0438\u043f\u0430 \u0444\u0438\u0433\u0443\u0440: \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f, \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0438\u043b\u0438 \u0441\u0440\u0435\u0434\u043d\u044f\u044f. \u0422\u0430\u043a \u0436\u0435, \u0444\u0438\u0433\u0443\u0440\u044b \u043c\u043e\u0436\u0435\u0442 \u043d\u0435 \u0431\u044b\u0442\u044c \u0432 \u044f\u0447\u0435\u0439\u043a\u0435.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0434\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c. \u041a\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0440\u0438\u0448\u043b\u043e \u043d\u0435 welcome \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0430 gameStatus? \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043f\u0435\u0440\u0432\u044b\u043c \u043f\u043e\u043b\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c. <\/p>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0432 \u0444\u0430\u0439\u043b <code>message.dart<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>message.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">class Message {   final MessageType type;   final WelcomeMessage? welcomeMessage;   final Move? move;   final GameStatus? gameStatus;    Message(this.type, {this.welcomeMessage, this.move, this.gameStatus});    factory Message.fromJson(Map&lt;String, dynamic> json) {     return Message(       MessageType.values.firstWhere((e) => e.toString() == json['type']),       gameStatus: json.containsKey('gameStatus') ? GameStatus.fromJson(json['gameStatus']) : null,       welcomeMessage:           json.containsKey('welcomeMessage') ? WelcomeMessage.fromJson(json['welcomeMessage']) : null,       move:            json.containsKey('move') ? Move.fromJson(json['move']) : null,     );   }    Map&lt;String, dynamic> toJson() {     final Map&lt;String, dynamic> data = {'type': type.toString()};     if (gameStatus != null) {       data['gameStatus'] = gameStatus!.toJson();     }     if (welcomeMessage != null) {       data['welcomeMessage'] = welcomeMessage!.toJson();     }     if (move != null) {       data['move'] = move!.toJson();     }     return data;   }    String toJsonString() {     final jsonString = jsonEncode(toJson());     final base2e15String = Base2e15.encode(jsonString.codeUnits);     return base2e15String;   }    factory Message.fromJsonString(String jsonString) {     final base2e15Bytes = Base2e15.decode(jsonString);     final base2e15String = String.fromCharCodes(base2e15Bytes);     final jsonData = jsonDecode(base2e15String);     return Message.fromJson(jsonData);   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043e\u043e\u0431\u0449\u0435, \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c handle \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435. \u041d\u043e \u0438 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043f\u0435\u0440\u0435\u0441\u043b\u0430\u043b\u0438. \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u0433\u0443\u0440\u0443 <code>dart<\/code> \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0442 \u043f\u043e\u0447\u0435\u043c\u0443 \u043c\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043d\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439, \u0441 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435\u043c \u0432\u044b\u0441\u043b\u0443\u0448\u0430\u044e.<\/p>\n<p>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435:<\/p>\n<ul>\n<li>\n<p><code>final MessageType type;<\/code> &#8212; \u0442\u0438\u043f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u043f\u0440\u0438\u0448\u043b\u043e.<\/p>\n<\/li>\n<li>\n<p> <code>final WelcomeMessage? welcomeMessage;<br \/> final Move? move;<br \/> final GameStatus? gameStatus;<\/code><\/p>\n<p>\u042d\u0442\u043e \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430. \u041e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c null. \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435: <code>Message(this.type, {this.welcomeMessage, this.move, this.gameStatus});<\/code> &#8212; \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0447\u0442\u043e \u044d\u0442\u0438 \u043f\u043e\u043b\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u044b \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0443\u0441\u0442\u044b\u043c\u0438. <\/p>\n<\/li>\n<li>\n<p><code>factory Message.fromJson<\/code>  &#8212; \u0442\u0443\u0442 \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e. \u0415\u0441\u043b\u0438 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438 \u0431\u044b\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u043d \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 <code>MessageType<\/code>, \u0442\u043e \u043c\u044b \u0435\u0433\u043e \u043f\u0430\u0440\u0441\u0438\u043c \u0438\u0437 json \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 <code>toJson()<\/code>  &#8212; \u0435\u0441\u043b\u0438 \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u044f \u043d\u0435 \u043f\u0443\u0441\u0442\u044b\u0435, \u0442\u043e \u043c\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0432 json.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438 <code>String toJsonString()<\/code>\u0438 <code>factory Message.fromJsonString(String jsonString)<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\\\u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 <code>base2e15<\/code> \u0438\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>\u0421\u0430\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u044b <code>WelcomeMessage<\/code>, <code>Move<\/code>, <code>GameStatus<\/code> :<\/p>\n<details class=\"spoiler\">\n<summary>welcome_message.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'player_role.dart';  class WelcomeMessage {   WelcomeMessage(this.clientId, this.canPlay, this.playerRole);   final String clientId;   final bool canPlay;   final PlayerRole playerRole;    factory WelcomeMessage.fromJson(Map&lt;String, dynamic> json) {     return WelcomeMessage(       json['clientId'],       json['canPlay'],       PlayerRole.values.byName(json['playerRole']),     );   }    Map&lt;String, dynamic> toJson() => {         'clientId': clientId,         'canPlay': canPlay,         'playerRole': playerRole.name,       }; }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>move.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'figure_type.dart';  class Move {   Move(this.clientId, this.sourceCellId, this.targetCellId, this.figureType,       {this.canPut});   String clientId;   int sourceCellId;   int targetCellId;   FigureType figureType;   bool? canPut;    factory Move.fromJson(Map&lt;String, dynamic> json) => Move(         json['clientId'],         json['sourceCellId'],         json['targetCellId'],         FigureType.values.byName(json['figureType']),         canPut: json.containsKey('canPut') ? json['canPut'] : null,       );    Map&lt;String, dynamic> toJson() {     final Map&lt;String, dynamic> data = {       'clientId': clientId,       'sourceCellId': sourceCellId,       'targetCellId': targetCellId,       'figureType': figureType.name,     };     if (canPut != null) {       data['canPut'] = canPut;     }     return data;   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>game_status.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'board.dart';  class GameStatus {   GameStatus(this.board, {this.winnerId});   Board board;   String? winnerId;    factory GameStatus.fromJson(Map&lt;String, dynamic> json) {     return GameStatus(       Board.fromJson(json['board']),       winnerId: json.containsKey('winnerId') ? json['winnerId'] : null,     );   }    Map&lt;String, dynamic> toJson() {     final Map&lt;String, dynamic> data = {       'board': board.toJson(),     };     if (winnerId != null) {       data['winnerId'] = winnerId;     }     return data;   } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u0430\u043a \u0432\u044b \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>GameStatus<\/code> \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 Board. \u041c\u044b \u043a \u043d\u0435\u043c\u0443 \u0441\u043a\u043e\u0440\u043e \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e. \u0412\u0441\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u0445\u043e\u0436\u0438. \u0412 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u0445 <code>fromJson<\/code> \u0438 <code>toJson<\/code>  \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u043f\u043e\u043b\u0435\u0439 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438\u0437\\\u0432 json \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0441\u0435\u0442\u0438.<\/p>\n<p>\u041f\u0440\u043e\u0439\u0434\u0435\u043c\u0441\u044f \u043f\u043e \u043f\u043e\u043b\u044f\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u0432:<\/p>\n<ul>\n<li>\n<p><code>class WelcomeMessage<\/code>:<\/p>\n<ul>\n<li>\n<p><code>final String clientId<\/code> &#8212; \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c \u043a\u043b\u0438\u0435\u043d\u0442\u0443 \u0435\u0433\u043e \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440<\/p>\n<\/li>\n<li>\n<p><code>final bool canPlay<\/code> &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0435\u0440 \u0437\u043d\u0430\u0435\u0442 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043e. \u0418 \u0435\u0441\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u0434\u0432\u0443\u0445, \u0442\u043e \u0438\u0433\u0440\u043e\u043a \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u0433\u0440\u0430\u0442\u044c. <\/p>\n<\/li>\n<li>\n<p><code>final PlayerRole playerRole;<\/code> &#8212; \u0437\u0430 \u0441\u0442\u043e\u043b\u043e\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0432\u0430 \u043c\u0435\u0441\u0442\u0430 &#8212; \u0432\u0435\u0440\u0445\u043d\u0438\u0439 \u0438\u0433\u0440\u043e\u043a \u0438 \u043d\u0438\u0436\u043d\u0438\u0439. \u0422\u0430\u043a \u0436\u0435, \u0435\u0441\u0442\u044c \u0440\u043e\u043b\u044c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u0444\u0438\u0433\u0443\u0440\u044b, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0437\u0430 \u0438\u0433\u0440\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>class Move<\/code>:<\/p>\n<ul>\n<li>\n<p>\u00a0<code>String clientId<\/code> &#8212; \u0442\u0430\u043a \u043a\u043b\u0438\u0435\u043d\u0442 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0447\u0442\u043e \u0441\u0445\u043e\u0434\u0438\u043b \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d<\/p>\n<\/li>\n<li>\n<p><code>int sourceCellId<\/code> &#8212; \u0438\u0437 \u043a\u0430\u043a\u043e\u0439 \u044f\u0447\u0435\u0439\u043a\u0438 \u0431\u044b\u043b\u0430 \u0432\u0437\u044f\u0442\u0430 \u0444\u0438\u0433\u0443\u0440\u0430<\/p>\n<\/li>\n<li>\n<p><code>int targetCellId<\/code> &#8212; \u0432 \u043a\u0430\u043a\u0443\u044e \u044f\u0447\u0435\u0439\u043a\u0443 \u044d\u0442\u0443 \u0444\u0438\u0433\u0443\u0440\u0443 \u0445\u043e\u0447\u0435\u0442 \u0438\u0433\u0440\u043e\u043a \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c<\/p>\n<\/li>\n<li>\n<p><code>FigureType figureType<\/code>&#8212; \u0442\u0438\u043f \u0444\u0438\u0433\u0443\u0440\u044b (\u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f, \u0441\u0440\u0435\u0434\u043d\u044f\u044f, \u0431\u043e\u043b\u044c\u0448\u0430\u044f)<\/p>\n<\/li>\n<li>\n<p><code>bool? canPut<\/code>&#8212; \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u043b\u0438\u0435\u043d\u0442 \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442. \u0415\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0438 true \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0445\u043e\u0434 \u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d \u0438 false \u0435\u0441\u043b\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d.<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><code>class GameStatus<\/code>:<\/p>\n<ul>\n<li>\n<p><code>String? winnerId<\/code> &#8212; \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435 \u0438 \u0440\u0430\u0432\u043d\u043e <code>null<\/code> \u043f\u043e\u043a\u0430 \u0432 \u0438\u0433\u0440\u0435 \u043d\u0435\u0442 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044f. \u0415\u0441\u043b\u0438 \u043f\u043e\u0431\u0435\u0434\u0438\u0442\u0435\u043b\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0441\u044f, \u0442\u043e \u0442\u0443\u0442 \u0431\u0443\u0434\u0435\u0442 <code>clientId<\/code> \u043f\u043e\u0431\u0435\u0434\u0438\u0432\u0448\u0435\u0433\u043e \u0438\u0433\u0440\u043e\u043a\u0430<\/p>\n<\/li>\n<li>\n<p><code>Board board<\/code>&#8212; \u0442\u0443\u0442 \u0436\u0438\u0432\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. <\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>\u0422\u0430\u043a \u0436\u0435 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u0444\u0438\u0433\u0443\u0440 &#8212; \u043e\u043d \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442 \u0438 \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>figure.dart<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"dart\">import 'figure_type.dart';  class Figure {<\/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-351647","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/351647","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=351647"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/351647\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=351647"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=351647"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=351647"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}