{"id":21960,"date":"2025-09-05T09:30:00","date_gmt":"2025-09-05T00:30:00","guid":{"rendered":"https:\/\/itport.cloud\/?p=21960"},"modified":"2025-08-18T17:37:01","modified_gmt":"2025-08-18T08:37:01","slug":"post-21960","status":"publish","type":"post","link":"https:\/\/itport.cloud\/?p=21960","title":{"rendered":"\u3010\u7b2c\u4e8c\u56de\u3011C#\u3067\u30c6\u30c8\u30ea\u30b9\u4f5c\u6210"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\" id=\"e79baee6aca1-1\">\u76ee\u6b21<\/h2>\n\n\n\n<p><a href=\"#1\" data-type=\"internal\" data-id=\"#1\">\u524d\u56de\u306e\u304a\u3055\u3089\u3044<\/a><br><a href=\"#2\" data-type=\"internal\" data-id=\"#2\">Controller\u5b9f\u88c5<\/a><br><a href=\"#3\" data-type=\"internal\" data-id=\"#3\">\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u6709\u52b9\u5316<\/a><br><a href=\"#4\" data-type=\"internal\" data-id=\"#4\">View\u5b9f\u88c5<\/a><br><a href=\"#5\" data-type=\"internal\" data-id=\"#5\">\u5b9f\u884c<\/a><br><a href=\"#6\" data-type=\"internal\" data-id=\"#6\">\u307e\u3068\u3081<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"1\">\u524d\u56de\u306e\u304a\u3055\u3089\u3044<\/h2>\n\n\n\n<p>\u524d\u56de\u306fModel\u90e8\u5206\u306e\u4f5c\u6210\u3092\u3057\u307e\u3057\u305f\u3002<br>\u5177\u4f53\u7684\u306b\u306f\u4ee5\u4e0b\u306e\u30af\u30e9\u30b9\u3068\u306a\u308a\u307e\u3059\u3002<br> 1,Tetrimino.cs\u3000\u30c6\u30c8\u30ea\u30df\u30ce\uff08\u843d\u3061\u3066\u304f\u308b\u30d6\u30ed\u30c3\u30af\uff09<br>2,GameBoard.cs\u3000\u30b2\u30fc\u30e0\u76e4\u306e\u7ba1\u7406<br>3,TetrisGame.cs\u3000\u30b2\u30fc\u30e0\u5168\u4f53\u306e\u5236\u5fa1 <br>\u4eca\u56de\u306fController\u3068View\u3092\u4f5c\u6210\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"2\">Controller\u5b9f\u88c5<\/h2>\n\n\n\n<p>\u307e\u305a\u306f GameController\u3092\u5b9f\u88c5\u3057\u3066\u3044\u304d\u307e\u3059\u3002<br>Controllers\u30d5\u30a9\u30eb\u30c0\u306b\u65b0\u3057\u3044\u30af\u30e9\u30b9\u3092\u4f5c\u6210\u3057\u3001\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u3092\u66f8\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using Microsoft.AspNetCore.Mvc;\nusing TetrisGame.Models;\nusing System.Text.Json;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace TetrisGame.Controllers\n{\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ \u30c6\u30c8\u30ea\u30b9\u30b2\u30fc\u30e0\u306eWebAPI\u5236\u5fa1\u3092\u884c\u3046\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\n    \/\/\/ &lt;\/summary&gt;\n    public class GameController : Controller\n    {\n        \/\/ \u30bb\u30c3\u30b7\u30e7\u30f3\u30ad\u30fc\u5b9a\u6570\n        private const string GAME_SESSION_KEY = \"TetrisGameState\";\n        private const string GAME_ID_KEY = \"TetrisGameId\";\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30b2\u30fc\u30e0\u306e\u30e1\u30a4\u30f3\u753b\u9762\u3092\u8868\u793a\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u30b2\u30fc\u30e0\u753b\u9762\u306eView&lt;\/returns&gt;\n        public IActionResult Index()\n        {\n            try\n            {\n                \/\/ \u65b0\u3057\u3044\u30b2\u30fc\u30e0\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u958b\u59cb\n                var gameId = Guid.NewGuid().ToString();\n                HttpContext.Session.SetString(GAME_ID_KEY, gameId);\n\n                \/\/ \u30bb\u30c3\u30b7\u30e7\u30f3\u60c5\u5831\u3092View\u306b\u6e21\u3059\n                ViewBag.GameId = gameId;\n                ViewBag.SessionTimeout = 30; \/\/ \u30c7\u30d5\u30a9\u30eb\u30c8\u502430\u5206\n\n                Console.WriteLine($\"&#91;DEBUG] Index: \u65b0\u3057\u3044\u30bb\u30c3\u30b7\u30e7\u30f3\u958b\u59cb - GameId: {gameId}\");\n                return View();\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] Index\u4f8b\u5916: {ex.Message}\");\n                \/\/ \u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u307e\u305f\u306f\u30c7\u30d5\u30a9\u30eb\u30c8\u72b6\u614b\u3067View\u3092\u8fd4\u3059\n                ViewBag.GameId = Guid.NewGuid().ToString();\n                ViewBag.SessionTimeout = 30;\n                return View();\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u65b0\u3057\u3044\u30b2\u30fc\u30e0\u3092\u958b\u59cb\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u30b2\u30fc\u30e0\u521d\u671f\u72b6\u614b\u306eJSON&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult StartNewGame()\n        {\n            Console.WriteLine(\"&#91;DEBUG] StartNewGame\u958b\u59cb\");\n\n            try\n            {\n                var game = new Models.TetrisGame();\n                Console.WriteLine($\"&#91;DEBUG] \u30b2\u30fc\u30e0\u4f5c\u6210\u6210\u529f: Board={game.Board.Board?.Length}x{game.Board.Board?&#91;0]?.Length}\");\n                Console.WriteLine($\"&#91;DEBUG] CurrentPiece: {game.CurrentPiece?.Type} at ({game.CurrentPiece?.X},{game.CurrentPiece?.Y})\");\n\n                SaveGameToSession(game);\n                Console.WriteLine(\"&#91;DEBUG] \u30bb\u30c3\u30b7\u30e7\u30f3\u4fdd\u5b58\u5b8c\u4e86\");\n\n                var gameState = GetGameStateForClient(game);\n                Console.WriteLine(\"&#91;DEBUG] \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u72b6\u614b\u4f5c\u6210\u5b8c\u4e86\");\n\n                return Json(new\n                {\n                    success = true,\n                    gameState = gameState,\n                    message = \"\u65b0\u3057\u3044\u30b2\u30fc\u30e0\u3092\u958b\u59cb\u3057\u307e\u3057\u305f\"\n                });\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] StartNewGame\u4f8b\u5916: {ex.Message}\");\n                Console.WriteLine($\"&#91;ERROR] \u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9: {ex.StackTrace}\");\n                return Json(new\n                {\n                    success = false,\n                    error = ex.Message\n                });\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u73fe\u5728\u306e\u30b2\u30fc\u30e0\u72b6\u614b\u3092\u53d6\u5f97\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u30b2\u30fc\u30e0\u72b6\u614b\u306eJSON&lt;\/returns&gt;\n        &#91;HttpGet]\n        public IActionResult GetGameState()\n        {\n            try\n            {\n                var game = LoadGameFromSession();\n                if (game == null)\n                {\n                    return Json(new\n                    {\n                        success = false,\n                        error = \"\u30b2\u30fc\u30e0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u65b0\u3057\u3044\u30b2\u30fc\u30e0\u3092\u958b\u59cb\u3057\u3066\u304f\u3060\u3055\u3044\u3002\",\n                        needsNewGame = true\n                    });\n                }\n\n                var gameState = GetGameStateForClient(game);\n\n                return Json(new\n                {\n                    success = true,\n                    gameState = gameState\n                });\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] GetGameState\u4f8b\u5916: {ex.Message}\");\n                return Json(new\n                {\n                    success = false,\n                    error = ex.Message,\n                    needsNewGame = true\n                });\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30c6\u30c8\u30ed\u30df\u30ce\u3092\u5de6\u306b\u79fb\u52d5\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u79fb\u52d5\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult MoveLeft()\n        {\n            return HandleGameAction(game =&gt; game.MoveLeft(), \"\u5de6\u79fb\u52d5\");\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30c6\u30c8\u30ed\u30df\u30ce\u3092\u53f3\u306b\u79fb\u52d5\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u79fb\u52d5\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult MoveRight()\n        {\n            return HandleGameAction(game =&gt; game.MoveRight(), \"\u53f3\u79fb\u52d5\");\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30c6\u30c8\u30ed\u30df\u30ce\u3092\u4e0b\u306b\u79fb\u52d5\uff08\u30bd\u30d5\u30c8\u30c9\u30ed\u30c3\u30d7\uff09\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u79fb\u52d5\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult MoveDown()\n        {\n            return HandleGameAction(game =&gt; game.MoveDown(), \"\u4e0b\u79fb\u52d5\");\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30c6\u30c8\u30ed\u30df\u30ce\u3092\u56de\u8ee2\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u56de\u8ee2\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult RotatePiece()\n        {\n            return HandleGameAction(game =&gt; game.RotatePiece(), \"\u56de\u8ee2\");\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30cf\u30fc\u30c9\u30c9\u30ed\u30c3\u30d7\uff08\u4e00\u6c17\u306b\u5e95\u307e\u3067\uff09\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u30c9\u30ed\u30c3\u30d7\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult HardDrop()\n        {\n            return HandleGameAction(game =&gt;\n            {\n                var dropDistance = game.HardDrop();\n                return dropDistance &gt;= 0; \/\/ 0\u3067\u3082\u6210\u529f\u3068\u3059\u308b\n            }, \"\u30cf\u30fc\u30c9\u30c9\u30ed\u30c3\u30d7\");\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30b2\u30fc\u30e0\u3092\u4e00\u6642\u505c\u6b62\/\u518d\u958b\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u64cd\u4f5c\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult TogglePause()\n        {\n            try\n            {\n                var game = LoadGameFromSession();\n                if (game == null)\n                {\n                    return Json(new { success = false, error = \"\u30b2\u30fc\u30e0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\", needsNewGame = true });\n                }\n\n                game.TogglePause();\n                SaveGameToSession(game);\n\n                var gameState = GetGameStateForClient(game);\n\n                return Json(new\n                {\n                    success = true,\n                    gameState = gameState,\n                    message = game.IsPaused ? \"\u30b2\u30fc\u30e0\u3092\u4e00\u6642\u505c\u6b62\u3057\u307e\u3057\u305f\" : \"\u30b2\u30fc\u30e0\u3092\u518d\u958b\u3057\u307e\u3057\u305f\"\n                });\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] TogglePause\u4f8b\u5916: {ex.Message}\");\n                return Json(new { success = false, error = ex.Message });\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30b2\u30fc\u30e0\u3092\u30ea\u30bb\u30c3\u30c8\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u30ea\u30bb\u30c3\u30c8\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult ResetGame()\n        {\n            try\n            {\n                var game = LoadGameFromSession();\n                if (game == null)\n                {\n                    \/\/ \u30b2\u30fc\u30e0\u304c\u5b58\u5728\u3057\u306a\u3044\u5834\u5408\u306f\u65b0\u898f\u4f5c\u6210\n                    return StartNewGame();\n                }\n\n                game.Reset();\n                SaveGameToSession(game);\n\n                var gameState = GetGameStateForClient(game);\n\n                return Json(new\n                {\n                    success = true,\n                    gameState = gameState,\n                    message = \"\u30b2\u30fc\u30e0\u3092\u30ea\u30bb\u30c3\u30c8\u3057\u307e\u3057\u305f\"\n                });\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] ResetGame\u4f8b\u5916: {ex.Message}\");\n                return Json(new { success = false, error = ex.Message });\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30b2\u30fc\u30e0\u72b6\u614b\u3092\u66f4\u65b0\uff08\u81ea\u52d5\u843d\u4e0b\u306a\u3069\uff09\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u66f4\u65b0\u5f8c\u306e\u30b2\u30fc\u30e0\u72b6\u614b&lt;\/returns&gt;\n        &#91;HttpPost]\n        public IActionResult UpdateGame()\n        {\n            try\n            {\n                var game = LoadGameFromSession();\n                if (game == null)\n                {\n                    return Json(new { success = false, error = \"\u30b2\u30fc\u30e0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\", needsNewGame = true });\n                }\n\n                \/\/ \u30b2\u30fc\u30e0\u72b6\u614b\u3092\u66f4\u65b0\uff08\u81ea\u52d5\u843d\u4e0b\u51e6\u7406\uff09\n                game.Update();\n                SaveGameToSession(game);\n\n                var gameState = GetGameStateForClient(game);\n\n                return Json(new\n                {\n                    success = true,\n                    gameState = gameState\n                });\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] UpdateGame\u4f8b\u5916: {ex.Message}\");\n                return Json(new { success = false, error = ex.Message });\n            }\n        }\n\n        #region \u30d7\u30e9\u30a4\u30d9\u30fc\u30c8\u30d8\u30eb\u30d1\u30fc\u30e1\u30bd\u30c3\u30c9\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30b2\u30fc\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u5171\u901a\u51e6\u7406\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;param name=\"action\"&gt;\u5b9f\u884c\u3059\u308b\u30a2\u30af\u30b7\u30e7\u30f3&lt;\/param&gt;\n        \/\/\/ &lt;param name=\"actionName\"&gt;\u30a2\u30af\u30b7\u30e7\u30f3\u540d\uff08\u30ed\u30b0\u7528\uff09&lt;\/param&gt;\n        \/\/\/ &lt;returns&gt;\u51e6\u7406\u7d50\u679c\u306eJSON&lt;\/returns&gt;\n        private IActionResult HandleGameAction(Func&lt;Models.TetrisGame, bool&gt; action, string actionName)\n        {\n            try\n            {\n                var game = LoadGameFromSession();\n                if (game == null)\n                {\n                    return Json(new { success = false, error = \"\u30b2\u30fc\u30e0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\", needsNewGame = true });\n                }\n\n                if (game.IsGameOver)\n                {\n                    return Json(new\n                    {\n                        success = false,\n                        error = \"\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc\u3067\u3059\",\n                        gameState = GetGameStateForClient(game)\n                    });\n                }\n\n                if (game.IsPaused)\n                {\n                    return Json(new\n                    {\n                        success = false,\n                        error = \"\u30b2\u30fc\u30e0\u304c\u4e00\u6642\u505c\u6b62\u4e2d\u3067\u3059\",\n                        gameState = GetGameStateForClient(game)\n                    });\n                }\n\n                \/\/ \u30a2\u30af\u30b7\u30e7\u30f3\u3092\u5b9f\u884c\n                bool actionResult = action(game);\n\n                \/\/ \u30bb\u30c3\u30b7\u30e7\u30f3\u306b\u4fdd\u5b58\n                SaveGameToSession(game);\n\n                \/\/ \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u7528\u306e\u72b6\u614b\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\n                var gameState = GetGameStateForClient(game);\n\n                return Json(new\n                {\n                    success = true,\n                    actionResult = actionResult,\n                    gameState = gameState,\n                    message = $\"{actionName}\u3092\u5b9f\u884c\u3057\u307e\u3057\u305f\"\n                });\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] HandleGameAction ({actionName}) \u4f8b\u5916: {ex.Message}\");\n                return Json(new\n                {\n                    success = false,\n                    error = ex.Message\n                });\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30bb\u30c3\u30b7\u30e7\u30f3\u304b\u3089\u30b2\u30fc\u30e0\u72b6\u614b\u3092\u8aad\u307f\u8fbc\u307f\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;returns&gt;\u30b2\u30fc\u30e0\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3001\u307e\u305f\u306f null&lt;\/returns&gt;\n        private Models.TetrisGame? LoadGameFromSession()\n        {\n            try\n            {\n                var gameJson = HttpContext.Session.GetString(GAME_SESSION_KEY);\n                if (string.IsNullOrEmpty(gameJson))\n                {\n                    Console.WriteLine(\"&#91;DEBUG] \u30bb\u30c3\u30b7\u30e7\u30f3\u306b\u30b2\u30fc\u30e0\u30c7\u30fc\u30bf\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\");\n                    return null;\n                }\n\n                \/\/ JSON\u304b\u3089\u30b2\u30fc\u30e0\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u5fa9\u5143\n                var options = new JsonSerializerOptions\n                {\n                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n                    WriteIndented = false\n                };\n\n                var game = JsonSerializer.Deserialize&lt;Models.TetrisGame&gt;(gameJson, options);\n                Console.WriteLine($\"&#91;DEBUG] \u30bb\u30c3\u30b7\u30e7\u30f3\u304b\u3089\u30b2\u30fc\u30e0\u5fa9\u5143\u6210\u529f: {game?.ToString()}\");\n                return game;\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] \u30bb\u30c3\u30b7\u30e7\u30f3\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc: {ex.Message}\");\n                \/\/ \u30c7\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u306b\u5931\u6557\u3057\u305f\u5834\u5408\u306fnull\u3092\u8fd4\u3059\n                return null;\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30b2\u30fc\u30e0\u72b6\u614b\u3092\u30bb\u30c3\u30b7\u30e7\u30f3\u306b\u4fdd\u5b58\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;param name=\"game\"&gt;\u4fdd\u5b58\u3059\u308b\u30b2\u30fc\u30e0\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9&lt;\/param&gt;\n        private void SaveGameToSession(Models.TetrisGame game)\n        {\n            try\n            {\n                var options = new JsonSerializerOptions\n                {\n                    WriteIndented = false,\n                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,\n                    DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull\n                };\n\n                var gameJson = JsonSerializer.Serialize(game, options);\n                HttpContext.Session.SetString(GAME_SESSION_KEY, gameJson);\n\n                Console.WriteLine($\"&#91;DEBUG] \u30bb\u30c3\u30b7\u30e7\u30f3\u4fdd\u5b58\u6210\u529f: \u30c7\u30fc\u30bf\u30b5\u30a4\u30ba {gameJson.Length} \u6587\u5b57\");\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] \u30bb\u30c3\u30b7\u30e7\u30f3\u4fdd\u5b58\u30a8\u30e9\u30fc: {ex.Message}\");\n                throw; \/\/ \u30a8\u30e9\u30fc\u3092\u518d\u30b9\u30ed\u30fc\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/ \u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u7528\u306e\u30b2\u30fc\u30e0\u72b6\u614b\u30c7\u30fc\u30bf\u3092\u4f5c\u6210\n        \/\/\/ &lt;\/summary&gt;\n        \/\/\/ &lt;param name=\"game\"&gt;\u30b2\u30fc\u30e0\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9&lt;\/param&gt;\n        \/\/\/ &lt;returns&gt;\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u7528\u306e\u72b6\u614b\u30aa\u30d6\u30b8\u30a7\u30af\u30c8&lt;\/returns&gt;\n        private object GetGameStateForClient(Models.TetrisGame game)\n        {\n            try\n            {\n                var gameState = new\n                {\n                    \/\/ \u30b2\u30fc\u30e0\u76e4\u306e\u72b6\u614b\n                    board = game.Board.Board,\n\n                    \/\/ \u73fe\u5728\u306e\u30d4\u30fc\u30b9\u60c5\u5831\n                    currentPiece = game.CurrentPiece != null ? new\n                    {\n                        type = game.CurrentPiece.Type.ToString(),\n                        x = game.CurrentPiece.X,\n                        y = game.CurrentPiece.Y,\n                        rotation = game.CurrentPiece.Rotation,\n                        shape = game.CurrentPiece.Shape\n                    } : null,\n\n                    \/\/ \u6b21\u306e\u30d4\u30fc\u30b9\u60c5\u5831\n                    nextPiece = game.NextPiece != null ? new\n                    {\n                        type = game.NextPiece.Type.ToString(),\n                        shape = game.NextPiece.Shape\n                    } : null,\n\n                    \/\/ \u30b9\u30b3\u30a2\u7b49\u306e\u60c5\u5831\n                    score = game.Score,\n                    lines = game.Lines,\n                    level = game.Level,\n\n                    \/\/ \u30b2\u30fc\u30e0\u72b6\u614b\n                    isGameOver = game.IsGameOver,\n                    isPaused = game.IsPaused,\n\n                    \/\/ \u30bf\u30a4\u30df\u30f3\u30b0\u60c5\u5831\n                    dropInterval = game.DropInterval,\n                    lastDropTime = game.LastDropTime.ToString(\"yyyy-MM-dd HH:mm:ss.fff\"),\n\n                    \/\/ \u8ffd\u52a0\u60c5\u5831\n                    ghostY = game.GetGhostPieceY() \/\/ \u30b4\u30fc\u30b9\u30c8\u30d4\u30fc\u30b9\u7528\n                };\n\n                return gameState;\n            }\n            catch (Exception ex)\n            {\n                Console.WriteLine($\"&#91;ERROR] GetGameStateForClient\u4f8b\u5916: {ex.Message}\");\n                throw;\n            }\n        }\n\n        #endregion\n    }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"3\">\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u6709\u52b9\u5316<\/h2>\n\n\n\n<p>\u7d9a\u3051\u3066\u30bb\u30c3\u30b7\u30e7\u30f3\u6a5f\u80fd\u306e\u6709\u52b9\u5316\u3092\u884c\u3044\u307e\u3059\u3002<br>\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u6709\u52b9\u5316\u3059\u308b\u305f\u3081\u306bProgram.cs \u306e\u4fee\u6b63\u3092\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u4fee\u6b63\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>var builder = WebApplication.CreateBuilder(args);\n\n\/\/ MVC \u30b5\u30fc\u30d3\u30b9\u3092\u8ffd\u52a0\nbuilder.Services.AddControllersWithViews();\n\n\/\/ \u30bb\u30c3\u30b7\u30e7\u30f3\u6a5f\u80fd\u3092\u8ffd\u52a0\nbuilder.Services.AddSession(options =&gt;\n{\n    options.IdleTimeout = TimeSpan.FromMinutes(30); \/\/ 30\u5206\u3067\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\n    options.Cookie.HttpOnly = true; \/\/ XSS\u5bfe\u7b56\n    options.Cookie.IsEssential = true; \/\/ GDPR\u5bfe\u7b56\n    options.Cookie.Name = \"TetrisGame.Session\"; \/\/ \u30bb\u30c3\u30b7\u30e7\u30f3Cookie\u540d\n});\n\n\/\/ \u30e1\u30e2\u30ea\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u8ffd\u52a0\uff08\u30bb\u30c3\u30b7\u30e7\u30f3\u7528\uff09\nbuilder.Services.AddMemoryCache();\n\nvar app = builder.Build();\n\n\/\/ Configure the HTTP request pipeline.\nif (!app.Environment.IsDevelopment())\n{\n    app.UseExceptionHandler(\"\/Home\/Error\");\n    \/\/ The default HSTS value is 30 days. You may want to change this for production scenarios.\n    app.UseHsts();\n}\n\napp.UseHttpsRedirection();\napp.UseStaticFiles();\n\napp.UseRouting();\n\n\/\/ \u30bb\u30c3\u30b7\u30e7\u30f3\u6a5f\u80fd\u3092\u6709\u52b9\u5316\uff08\u91cd\u8981\uff1aUseRouting\u306e\u5f8c\u3001UseEndpoints\u306e\u524d\uff09\napp.UseSession();\n\napp.UseAuthorization();\n\napp.MapControllerRoute(\n    name: \"default\",\n    pattern: \"{controller=Game}\/{action=Index}\/{id?}\"); \/\/ \u30c7\u30d5\u30a9\u30eb\u30c8\u3092GameController\u306b\u5909\u66f4\n\napp.Run();<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"4\">View\u5b9f\u88c5<\/h2>\n\n\n\n<p>\u7d9a\u3051\u3066View\u306e\u5b9f\u88c5\u3092\u884c\u3063\u3066\u3044\u304d\u307e\u3059\u3002<br>\u307e\u305a\u306f\u300cViews\u300d\u30d5\u30a9\u30eb\u30c0\u3092\u53f3\u30af\u30ea\u30c3\u30af\u3057\u3066\u8ffd\u52a0\uff1e\u65b0\u3057\u3044\u30d5\u30a9\u30eb\u30c0\u30fc\u304b\u3089\u300cGame\u300d\u30d5\u30a9\u30eb\u30c0\u3092\u4f5c\u6210\u3057\u307e\u3059\u3002<br>\u7d9a\u3051\u3066\u300cGame\u300d\u30d5\u30a9\u30eb\u30c0\u3092\u53f3\u30af\u30ea\u30c3\u30af\u3057\u3066\u8ffd\u52a0\uff1e\u30d3\u30e5\u30fc\u3092\u4f5c\u6210\u3057\u540d\u524d\u3092Index\u3068\u3057\u3066\u4f5c\u6210\u3057\u307e\u3059\u3002<br>\u4f5c\u6210\u3057\u305fIndex\u306b\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u3092\u66f8\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@{\n    ViewData&#91;\"Title\"] = \"\u30c6\u30c8\u30ea\u30b9\u30b2\u30fc\u30e0\";\n}\n\n&lt;!DOCTYPE html&gt;\n&lt;html lang=\"ja\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"utf-8\" \/&gt;\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/&gt;\n    &lt;title&gt;@ViewData&#91;\"Title\"]&lt;\/title&gt;\n\n    &lt;style type=\"text\/css\"&gt;\n        \/* ========== \u57fa\u672c\u30b9\u30bf\u30a4\u30eb ========== *\/\n        * {\n            margin: 0;\n            padding: 0;\n            box-sizing: border-box;\n        }\n\n        body {\n            font-family: '\u30e1\u30a4\u30ea\u30aa', 'Hiragino Sans', Arial, sans-serif;\n            background-color: #0a0a0a;\n            color: white;\n            padding: 20px;\n        }\n\n        .container {\n            max-width: 1000px;\n            margin: 0 auto;\n        }\n\n        \/* ========== \u30d8\u30c3\u30c0\u30fc ========== *\/\n        .game-header {\n            text-align: center;\n            margin-bottom: 30px;\n        }\n\n        .game-title {\n            font-size: 2.5rem;\n            color: #00ffff;\n            text-shadow: 0 0 10px #00ffff;\n            margin-bottom: 10px;\n        }\n\n        \/* ========== \u30ec\u30a4\u30a2\u30a6\u30c8 ========== *\/\n        .game-content {\n            display: flex;\n            flex-direction: row;\n            gap: 30px;\n            margin-bottom: 30px;\n            justify-content: center;\n        }\n\n        .game-area {\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n        }\n\n        #tetris-board {\n            border: 3px solid #00ffff;\n            background-color: #111;\n            box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);\n        }\n\n        \/* ========== \u60c5\u5831\u30d1\u30cd\u30eb ========== *\/\n        .info-panel {\n            background-color: #1a1a1a;\n            border: 2px solid #333;\n            border-radius: 10px;\n            padding: 20px;\n            width: 300px;\n            height: fit-content;\n        }\n\n        .info-section {\n            margin-bottom: 25px;\n            padding-bottom: 15px;\n            border-bottom: 1px solid #333;\n        }\n\n            .info-section:last-child {\n                border-bottom: none;\n                margin-bottom: 0;\n            }\n\n        .info-title {\n            font-size: 0.9rem;\n            color: #00ffff;\n            margin-bottom: 8px;\n            text-transform: uppercase;\n            letter-spacing: 1px;\n        }\n\n        .info-value {\n            font-size: 1.5rem;\n            font-weight: bold;\n            color: white;\n        }\n\n        .next-piece-area {\n            text-align: center;\n        }\n\n        #next-piece {\n            border: 2px solid #555;\n            background-color: #0f0f0f;\n            margin: 10px auto;\n            display: block;\n        }\n\n        \/* ========== \u30dc\u30bf\u30f3 ========== *\/\n        .button-area {\n            text-align: center;\n            margin-bottom: 30px;\n        }\n\n        .game-button {\n            background: linear-gradient(135deg, #00ffff, #0080ff);\n            border: none;\n            border-radius: 8px;\n            color: white;\n            padding: 12px 24px;\n            margin: 0 5px 5px 5px;\n            font-size: 1rem;\n            font-weight: bold;\n            cursor: pointer;\n            transition: all 0.3s ease;\n            text-transform: uppercase;\n            letter-spacing: 1px;\n        }\n\n            .game-button:hover {\n                background: linear-gradient(135deg, #0080ff, #0060df);\n                transform: translateY(-2px);\n                box-shadow: 0 5px 15px rgba(0, 255, 255, 0.4);\n            }\n\n            .game-button:active {\n                transform: translateY(0);\n            }\n\n            .game-button:disabled {\n                background: #666;\n                cursor: not-allowed;\n                transform: none;\n                box-shadow: none;\n            }\n\n        \/* ========== \u64cd\u4f5c\u8aac\u660e ========== *\/\n        .controls-section {\n            background-color: #1a1a1a;\n            border-radius: 10px;\n            padding: 20px;\n            margin-bottom: 20px;\n        }\n\n        .controls-title {\n            color: #00ffff;\n            margin-bottom: 15px;\n            font-size: 1.2rem;\n        }\n\n        .control-list {\n            display: flex;\n            flex-direction: column;\n            gap: 10px;\n        }\n\n        .control-item {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            padding: 8px 0;\n            border-bottom: 1px solid #333;\n        }\n\n            .control-item:last-child {\n                border-bottom: none;\n            }\n\n        .control-key {\n            font-weight: bold;\n            color: #00ffff;\n            font-family: 'Courier New', monospace;\n        }\n\n        .control-action {\n            color: #ccc;\n        }\n\n        \/* ========== \u30b9\u30c6\u30fc\u30bf\u30b9\u30e1\u30c3\u30bb\u30fc\u30b8 ========== *\/\n        .status-message {\n            padding: 15px;\n            border-radius: 8px;\n            margin: 20px auto;\n            max-width: 500px;\n            text-align: center;\n            font-weight: bold;\n            display: none;\n        }\n\n        .status-success {\n            background-color: rgba(76, 175, 80, 0.2);\n            border: 1px solid #4caf50;\n            color: #4caf50;\n        }\n\n        .status-error {\n            background-color: rgba(244, 67, 54, 0.2);\n            border: 1px solid #f44336;\n            color: #f44336;\n        }\n\n        .status-info {\n            background-color: rgba(33, 150, 243, 0.2);\n            border: 1px solid #2196f3;\n            color: #2196f3;\n        }\n\n        \/* ========== \u30ec\u30b9\u30dd\u30f3\u30b7\u30d6\u30c7\u30b6\u30a4\u30f3\uff08\u4fee\u6b63\u7248\uff09 ========== *\/\n        \/* \u30bf\u30d6\u30ec\u30c3\u30c8\u7528 *\/\n        @@media screen and (max-width: 1024px) {\n            .container {\n                padding: 0 10px;\n            }\n\n            .game-content {\n                gap: 20px;\n            }\n\n            .info-panel {\n                width: 250px;\n            }\n        }\n\n        \/* \u30b9\u30de\u30fc\u30c8\u30d5\u30a9\u30f3\u7528 *\/\n        @@media screen and (max-width: 768px) {\n            body {\n                padding: 10px;\n            }\n\n            .game-title {\n                font-size: 2rem;\n            }\n\n            .game-content {\n                flex-direction: column;\n                align-items: center;\n                gap: 20px;\n            }\n\n            .info-panel {\n                width: 100%;\n                max-width: 400px;\n            }\n\n            #tetris-board {\n                width: 280px;\n                height: 560px;\n            }\n\n            .game-button {\n                display: block;\n                margin: 5px auto;\n                width: 200px;\n                padding: 15px 24px;\n            }\n\n            .control-list {\n                display: grid;\n                grid-template-columns: 1fr;\n                gap: 8px;\n            }\n        }\n\n        \/* \u5c0f\u3055\u3044\u30b9\u30de\u30fc\u30c8\u30d5\u30a9\u30f3\u7528 *\/\n        @@media screen and (max-width: 480px) {\n            .game-title {\n                font-size: 1.5rem;\n            }\n\n            #tetris-board {\n                width: 250px;\n                height: 500px;\n            }\n\n            .info-panel {\n                padding: 15px;\n            }\n\n            .info-value {\n                font-size: 1.2rem;\n            }\n\n            .game-button {\n                width: 100%;\n                max-width: 280px;\n            }\n        }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;div class=\"container\"&gt;\n        &lt;header class=\"game-header\"&gt;\n            &lt;h1 class=\"game-title\"&gt;? TETRIS GAME ?&lt;\/h1&gt;\n        &lt;\/header&gt;\n\n        &lt;main class=\"game-content\"&gt;\n            &lt;div class=\"game-area\"&gt;\n                &lt;canvas id=\"tetris-board\" width=\"300\" height=\"600\"&gt;\n                    \u304a\u4f7f\u3044\u306e\u30d6\u30e9\u30a6\u30b6\u306fCanvas\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093\u3002\n                &lt;\/canvas&gt;\n            &lt;\/div&gt;\n\n            &lt;aside class=\"info-panel\"&gt;\n                &lt;div class=\"info-section\"&gt;\n                    &lt;div class=\"info-title\"&gt;Score&lt;\/div&gt;\n                    &lt;div class=\"info-value\" id=\"score-display\"&gt;0&lt;\/div&gt;\n                &lt;\/div&gt;\n\n                &lt;div class=\"info-section\"&gt;\n                    &lt;div class=\"info-title\"&gt;Level&lt;\/div&gt;\n                    &lt;div class=\"info-value\" id=\"level-display\"&gt;1&lt;\/div&gt;\n                &lt;\/div&gt;\n\n                &lt;div class=\"info-section\"&gt;\n                    &lt;div class=\"info-title\"&gt;Lines&lt;\/div&gt;\n                    &lt;div class=\"info-value\" id=\"lines-display\"&gt;0&lt;\/div&gt;\n                &lt;\/div&gt;\n\n                &lt;div class=\"info-section next-piece-area\"&gt;\n                    &lt;div class=\"info-title\"&gt;Next Piece&lt;\/div&gt;\n                    &lt;canvas id=\"next-piece\" width=\"120\" height=\"120\"&gt;&lt;\/canvas&gt;\n                &lt;\/div&gt;\n\n                &lt;div class=\"info-section\"&gt;\n                    &lt;div class=\"info-title\"&gt;Status&lt;\/div&gt;\n                    &lt;div class=\"info-value\" id=\"game-status\"&gt;\u6e96\u5099\u4e2d&lt;\/div&gt;\n                &lt;\/div&gt;\n            &lt;\/aside&gt;\n        &lt;\/main&gt;\n\n        &lt;div class=\"button-area\"&gt;\n            &lt;button id=\"start-btn\" class=\"game-button\"&gt;? \u30b2\u30fc\u30e0\u958b\u59cb&lt;\/button&gt;\n            &lt;button id=\"pause-btn\" class=\"game-button\" disabled&gt;\u23f8\ufe0f \u4e00\u6642\u505c\u6b62&lt;\/button&gt;\n            &lt;button id=\"reset-btn\" class=\"game-button\"&gt;? \u30ea\u30bb\u30c3\u30c8&lt;\/button&gt;\n        &lt;\/div&gt;\n\n        &lt;section class=\"controls-section\"&gt;\n            &lt;h3 class=\"controls-title\"&gt;? \u64cd\u4f5c\u65b9\u6cd5&lt;\/h3&gt;\n            &lt;div class=\"control-list\"&gt;\n                &lt;div class=\"control-item\"&gt;\n                    &lt;span class=\"control-key\"&gt;\u2190 \u2192 (A D)&lt;\/span&gt;\n                    &lt;span class=\"control-action\"&gt;\u5de6\u53f3\u79fb\u52d5&lt;\/span&gt;\n                &lt;\/div&gt;\n                &lt;div class=\"control-item\"&gt;\n                    &lt;span class=\"control-key\"&gt;\u2193 (S)&lt;\/span&gt;\n                    &lt;span class=\"control-action\"&gt;\u9ad8\u901f\u843d\u4e0b&lt;\/span&gt;\n                &lt;\/div&gt;\n                &lt;div class=\"control-item\"&gt;\n                    &lt;span class=\"control-key\"&gt;\u2191 (W)&lt;\/span&gt;\n                    &lt;span class=\"control-action\"&gt;\u56de\u8ee2&lt;\/span&gt;\n                &lt;\/div&gt;\n                &lt;div class=\"control-item\"&gt;\n                    &lt;span class=\"control-key\"&gt;Space&lt;\/span&gt;\n                    &lt;span class=\"control-action\"&gt;\u30cf\u30fc\u30c9\u30c9\u30ed\u30c3\u30d7&lt;\/span&gt;\n                &lt;\/div&gt;\n                &lt;div class=\"control-item\"&gt;\n                    &lt;span class=\"control-key\"&gt;P&lt;\/span&gt;\n                    &lt;span class=\"control-action\"&gt;\u4e00\u6642\u505c\u6b62&lt;\/span&gt;\n                &lt;\/div&gt;\n            &lt;\/div&gt;\n        &lt;\/section&gt;\n\n        &lt;div id=\"status-message\" class=\"status-message\"&gt;&lt;\/div&gt;\n    &lt;\/div&gt;\n\n    &lt;script&gt;\n        console.log('? \u30c6\u30c8\u30ea\u30b9\u8aad\u307f\u8fbc\u307f\u958b\u59cb');\n\n        \/\/ \u30b0\u30ed\u30fc\u30d0\u30eb\u5909\u6570\n        let gameState = null;\n        let isGameRunning = false;\n        let gameLoopTimer = null;\n        let autoDropTimer = null;\n        let lastUpdateTime = 0;\n        let keyPressed = {};\n\n        \/\/ DOM\u8981\u7d20\n        const elements = {\n            tetrisBoard: document.getElementById('tetris-board'),\n            nextPiece: document.getElementById('next-piece'),\n            scoreDisplay: document.getElementById('score-display'),\n            levelDisplay: document.getElementById('level-display'),\n            linesDisplay: document.getElementById('lines-display'),\n            gameStatus: document.getElementById('game-status'),\n            startBtn: document.getElementById('start-btn'),\n            pauseBtn: document.getElementById('pause-btn'),\n            resetBtn: document.getElementById('reset-btn'),\n            statusMessage: document.getElementById('status-message')\n        };\n\n        const boardCtx = elements.tetrisBoard.getContext('2d');\n        const nextCtx = elements.nextPiece.getContext('2d');\n\n        \/\/ \u521d\u671f\u5316\n        document.addEventListener('DOMContentLoaded', function() {\n            console.log('? DOM\u8aad\u307f\u8fbc\u307f\u5b8c\u4e86');\n            setupEventListeners();\n            initializeCanvas();\n            console.log('\u2705 \u521d\u671f\u5316\u5b8c\u4e86');\n        });\n\n        function setupEventListeners() {\n            elements.startBtn.addEventListener('click', startNewGame);\n            elements.pauseBtn.addEventListener('click', togglePause);\n            elements.resetBtn.addEventListener('click', resetGame);\n\n            \/\/ \u30ad\u30fc\u30dc\u30fc\u30c9\u30a4\u30d9\u30f3\u30c8\uff08\u91cd\u8907\u9632\u6b62\u6a5f\u80fd\u4ed8\u304d\uff09\n            document.addEventListener('keydown', (e) =&gt; {\n                if (keyPressed&#91;e.key]) return; \/\/ \u91cd\u8907\u9632\u6b62\n                keyPressed&#91;e.key] = true;\n                handleKeyPress(e);\n            });\n\n            document.addEventListener('keyup', (e) =&gt; {\n                keyPressed&#91;e.key] = false;\n            });\n\n            window.addEventListener('beforeunload', stopAutoDropSystem);\n        }\n\n        function initializeCanvas() {\n            \/\/ \u30e1\u30a4\u30f3\u30dc\u30fc\u30c9\u521d\u671f\u5316\n            boardCtx.fillStyle = '#111';\n            boardCtx.fillRect(0, 0, elements.tetrisBoard.width, elements.tetrisBoard.height);\n\n            \/\/ \u30cd\u30af\u30b9\u30c8\u30d4\u30fc\u30b9\u521d\u671f\u5316\n            nextCtx.fillStyle = '#0f0f0f';\n            nextCtx.fillRect(0, 0, elements.nextPiece.width, elements.nextPiece.height);\n\n            drawGrid();\n        }\n\n        function drawGrid() {\n            const cellWidth = elements.tetrisBoard.width \/ 10;\n            const cellHeight = elements.tetrisBoard.height \/ 20;\n\n            boardCtx.strokeStyle = '#333';\n            boardCtx.lineWidth = 1;\n\n            \/\/ \u7e26\u7dda\n            for (let i = 0; i &lt;= 10; i++) {\n                const x = i * cellWidth;\n                boardCtx.beginPath();\n                boardCtx.moveTo(x, 0);\n                boardCtx.lineTo(x, elements.tetrisBoard.height);\n                boardCtx.stroke();\n            }\n\n            \/\/ \u6a2a\u7dda\n            for (let i = 0; i &lt;= 20; i++) {\n                const y = i * cellHeight;\n                boardCtx.beginPath();\n                boardCtx.moveTo(0, y);\n                boardCtx.lineTo(elements.tetrisBoard.width, y);\n                boardCtx.stroke();\n            }\n        }\n\n        async function startNewGame() {\n            console.log('? \u30b2\u30fc\u30e0\u958b\u59cb');\n            elements.gameStatus.textContent = '\u958b\u59cb\u4e2d...';\n\n            try {\n                const response = await fetch('\/Game\/StartNewGame', {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/json' }\n                });\n\n                const data = await response.json();\n                console.log('? \u30ec\u30b9\u30dd\u30f3\u30b9:', data);\n\n                if (data.success) {\n                    gameState = data.gameState;\n                    isGameRunning = true;\n                    lastUpdateTime = Date.now();\n\n                    updateUI();\n                    updateButtonStates(true);\n                    startAutoDropSystem();\n\n                    showStatusMessage('\u30b2\u30fc\u30e0\u958b\u59cb\uff01', 'success');\n                    console.log('\u2705 \u30b2\u30fc\u30e0\u958b\u59cb\u6210\u529f');\n                } else {\n                    showStatusMessage('\u30a8\u30e9\u30fc: ' + data.error, 'error');\n                }\n            } catch (error) {\n                console.error('\u274c \u901a\u4fe1\u30a8\u30e9\u30fc:', error);\n                showStatusMessage('\u901a\u4fe1\u30a8\u30e9\u30fc', 'error');\n            }\n        }\n\n        function startAutoDropSystem() {\n            console.log('\u23f0 \u81ea\u52d5\u843d\u4e0b\u30b7\u30b9\u30c6\u30e0\u958b\u59cb');\n            stopAutoDropSystem();\n\n            \/\/ \u63cf\u753b\u30eb\u30fc\u30d7\uff0860FPS\uff09\n            gameLoopTimer = setInterval(() =&gt; {\n                if (isGameRunning &amp;&amp; gameState &amp;&amp; !gameState.isGameOver &amp;&amp; !gameState.isPaused) {\n                    updateUI();\n                }\n            }, 1000 \/ 60);\n\n            \/\/ \u81ea\u52d5\u843d\u4e0b\u30eb\u30fc\u30d7\uff080.5\u79d2\u9593\u9694\uff09\n            autoDropTimer = setInterval(async () =&gt; {\n                if (isGameRunning &amp;&amp; gameState &amp;&amp; !gameState.isGameOver &amp;&amp; !gameState.isPaused) {\n                    await performAutoUpdate();\n                }\n            }, 500);\n        }\n\n        function stopAutoDropSystem() {\n            if (gameLoopTimer) {\n                clearInterval(gameLoopTimer);\n                gameLoopTimer = null;\n                console.log('\u23f0 \u63cf\u753b\u30eb\u30fc\u30d7\u505c\u6b62');\n            }\n            if (autoDropTimer) {\n                clearInterval(autoDropTimer);\n                autoDropTimer = null;\n                console.log('\u23f0 \u81ea\u52d5\u843d\u4e0b\u30eb\u30fc\u30d7\u505c\u6b62');\n            }\n        }\n\n        async function performAutoUpdate() {\n            try {\n                const response = await fetch('\/Game\/UpdateGame', {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/json' }\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    const oldY = gameState.currentPiece?.y;\n                    gameState = data.gameState;\n                    const newY = gameState.currentPiece?.y;\n\n                    if (oldY !== newY) {\n                        console.log(`\u2b07\ufe0f \u81ea\u52d5\u843d\u4e0b: Y ${oldY} \u2192 ${newY}`);\n                    }\n\n                    if (gameState.isGameOver) {\n                        handleGameOver();\n                    }\n\n                    lastUpdateTime = Date.now();\n                } else if (data.needsNewGame) {\n                    console.log('? \u30b2\u30fc\u30e0\u72b6\u614b\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093');\n                    showStatusMessage('\u30b2\u30fc\u30e0\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u5207\u308c\u307e\u3057\u305f', 'error');\n                    isGameRunning = false;\n                    updateButtonStates(false);\n                    stopAutoDropSystem();\n                }\n            } catch (error) {\n                console.error('\u274c \u81ea\u52d5\u66f4\u65b0\u30a8\u30e9\u30fc:', error);\n            }\n        }\n\n        function handleGameOver() {\n            console.log('? \u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc');\n            stopAutoDropSystem();\n            isGameRunning = false;\n            updateUI();\n            updateButtonStates(false);\n\n            setTimeout(() =&gt; {\n                const result = confirm(`\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc\uff01\\n\u6700\u7d42\u30b9\u30b3\u30a2: ${gameState.score.toLocaleString()}\\n\u6d88\u53bb\u30e9\u30a4\u30f3\u6570: ${gameState.lines}\\n\u30ec\u30d9\u30eb: ${gameState.level}\\n\\n\u3082\u3046\u4e00\u5ea6\u30d7\u30ec\u30a4\u3057\u307e\u3059\u304b\uff1f`);\n                if (result) {\n                    startNewGame();\n                }\n            }, 1000);\n        }\n\n        async function handleKeyPress(event) {\n            if (!isGameRunning || !gameState || gameState.isGameOver) return;\n\n            \/\/ \u4e00\u6642\u505c\u6b62\u4e2d\u3067\u3082P\u30ad\u30fc\u306f\u6709\u52b9\n            if (event.key.toLowerCase() === 'p') {\n                togglePause();\n                return;\n            }\n\n            if (gameState.isPaused) return;\n\n            let endpoint = null;\n\n            switch (event.key.toLowerCase()) {\n                case 'arrowleft':\n                case 'a':\n                    endpoint = '\/Game\/MoveLeft';\n                    break;\n                case 'arrowright':\n                case 'd':\n                    endpoint = '\/Game\/MoveRight';\n                    break;\n                case 'arrowdown':\n                case 's':\n                    endpoint = '\/Game\/MoveDown';\n                    break;\n                case 'arrowup':\n                case 'w':\n                    endpoint = '\/Game\/RotatePiece';\n                    break;\n                case ' ':\n                case 'spacebar':\n                    endpoint = '\/Game\/HardDrop';\n                    break;\n                default:\n                    return; \/\/ \u7121\u95a2\u4fc2\u306a\u30ad\u30fc\u306f\u7121\u8996\n            }\n\n            if (endpoint) {\n                event.preventDefault();\n                await sendGameAction(endpoint);\n            }\n        }\n\n        async function sendGameAction(endpoint) {\n            try {\n                const response = await fetch(endpoint, {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/json' }\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    gameState = data.gameState;\n                    updateUI();\n                    lastUpdateTime = Date.now();\n\n                    \/\/ \u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc\u30c1\u30a7\u30c3\u30af\n                    if (gameState.isGameOver) {\n                        handleGameOver();\n                    }\n                } else if (data.needsNewGame) {\n                    showStatusMessage('\u30b2\u30fc\u30e0\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u5207\u308c\u307e\u3057\u305f', 'error');\n                    isGameRunning = false;\n                    updateButtonStates(false);\n                    stopAutoDropSystem();\n                }\n            } catch (error) {\n                console.error('\u274c \u64cd\u4f5c\u30a8\u30e9\u30fc:', error);\n            }\n        }\n\n        async function togglePause() {\n            if (!gameState) return;\n\n            try {\n                const response = await fetch('\/Game\/TogglePause', {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/json' }\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    gameState = data.gameState;\n                    updateUI();\n                    updateButtonStates(isGameRunning);\n                    showStatusMessage(data.message, 'info');\n                }\n            } catch (error) {\n                console.error('\u274c \u4e00\u6642\u505c\u6b62\u30a8\u30e9\u30fc:', error);\n            }\n        }\n\n        async function resetGame() {\n            console.log('? \u30ea\u30bb\u30c3\u30c8\u958b\u59cb');\n            stopAutoDropSystem();\n\n            try {\n                const response = await fetch('\/Game\/ResetGame', {\n                    method: 'POST',\n                    headers: { 'Content-Type': 'application\/json' }\n                });\n\n                const data = await response.json();\n\n                if (data.success) {\n                    gameState = data.gameState;\n                    isGameRunning = true;\n                    lastUpdateTime = Date.now();\n\n                    updateUI();\n                    updateButtonStates(true);\n                    startAutoDropSystem();\n\n                    showStatusMessage('\u30ea\u30bb\u30c3\u30c8\u5b8c\u4e86', 'success');\n                    console.log('\u2705 \u30ea\u30bb\u30c3\u30c8\u5b8c\u4e86');\n                } else {\n                    showStatusMessage('\u30ea\u30bb\u30c3\u30c8\u306b\u5931\u6557\u3057\u307e\u3057\u305f', 'error');\n                }\n            } catch (error) {\n                console.error('\u274c \u30ea\u30bb\u30c3\u30c8\u30a8\u30e9\u30fc:', error);\n                showStatusMessage('\u30ea\u30bb\u30c3\u30c8\u30a8\u30e9\u30fc', 'error');\n            }\n        }\n\n        function updateUI() {\n            if (!gameState) return;\n\n            \/\/ \u30b9\u30b3\u30a2\u60c5\u5831\u306e\u66f4\u65b0\n            elements.scoreDisplay.textContent = gameState.score.toLocaleString();\n            elements.levelDisplay.textContent = gameState.level;\n            elements.linesDisplay.textContent = gameState.lines;\n\n            \/\/ \u30b2\u30fc\u30e0\u72b6\u614b\u306e\u8868\u793a\n            if (gameState.isGameOver) {\n                elements.gameStatus.textContent = '\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc';\n                elements.gameStatus.style.color = '#ff4444';\n            } else if (gameState.isPaused) {\n                elements.gameStatus.textContent = '\u4e00\u6642\u505c\u6b62\u4e2d';\n                elements.gameStatus.style.color = '#ffaa44';\n            } else {\n                elements.gameStatus.textContent = '\u30d7\u30ec\u30a4\u4e2d';\n                elements.gameStatus.style.color = '#44ff44';\n            }\n\n            drawGameBoard();\n            drawNextPiece();\n        }\n\n        function drawGameBoard() {\n            \/\/ \u80cc\u666f\u3092\u30af\u30ea\u30a2\n            boardCtx.fillStyle = '#111';\n            boardCtx.fillRect(0, 0, elements.tetrisBoard.width, elements.tetrisBoard.height);\n\n            if (gameState &amp;&amp; gameState.board) {\n                const cellWidth = elements.tetrisBoard.width \/ 10;\n                const cellHeight = elements.tetrisBoard.height \/ 20;\n\n                \/\/ \u56fa\u5b9a\u3055\u308c\u305f\u30d6\u30ed\u30c3\u30af\u3092\u63cf\u753b\n                for (let row = 0; row &lt; 20; row++) {\n                    for (let col = 0; col &lt; 10; col++) {\n                        const cellValue = gameState.board&#91;row]&#91;col];\n                        if (cellValue &gt; 0) {\n                            boardCtx.fillStyle = getBlockColor(cellValue);\n                            boardCtx.fillRect(\n                                col * cellWidth + 1,\n                                row * cellHeight + 1,\n                                cellWidth - 2,\n                                cellHeight - 2\n                            );\n                        }\n                    }\n                }\n\n                \/\/ \u30b4\u30fc\u30b9\u30c8\u30d4\u30fc\u30b9\u3092\u63cf\u753b\uff08\u73fe\u5728\u306e\u30d4\u30fc\u30b9\u304c\u3042\u308b\u5834\u5408\uff09\n                if (gameState.currentPiece &amp;&amp; gameState.ghostY !== undefined &amp;&amp; gameState.ghostY &gt; gameState.currentPiece.y) {\n                    const piece = gameState.currentPiece;\n                    boardCtx.fillStyle = 'rgba(255, 255, 255, 0.3)'; \/\/ \u534a\u900f\u660e\u306e\u767d\n\n                    for (let row = 0; row &lt; 4; row++) {\n                        for (let col = 0; col &lt; 4; col++) {\n                            if (piece.shape&#91;row] &amp;&amp; piece.shape&#91;row]&#91;col]) {\n                                const boardX = piece.x + col;\n                                const boardY = gameState.ghostY + row;\n\n                                if (boardX &gt;= 0 &amp;&amp; boardX &lt; 10 &amp;&amp; boardY &gt;= 0 &amp;&amp; boardY &lt; 20) {\n                                    boardCtx.fillRect(\n                                        boardX * cellWidth + 2,\n                                        boardY * cellHeight + 2,\n                                        cellWidth - 4,\n                                        cellHeight - 4\n                                    );\n                                }\n                            }\n                        }\n                    }\n                }\n\n                \/\/ \u73fe\u5728\u306e\u30d4\u30fc\u30b9\u3092\u63cf\u753b\n                if (gameState.currentPiece) {\n                    const piece = gameState.currentPiece;\n                    boardCtx.fillStyle = getBlockColor(getTetrominoTypeNumber(piece.type));\n\n                    for (let row = 0; row &lt; 4; row++) {\n                        for (let col = 0; col &lt; 4; col++) {\n                            if (piece.shape&#91;row] &amp;&amp; piece.shape&#91;row]&#91;col]) {\n                                const boardX = piece.x + col;\n                                const boardY = piece.y + row;\n\n                                if (boardX &gt;= 0 &amp;&amp; boardX &lt; 10 &amp;&amp; boardY &gt;= 0 &amp;&amp; boardY &lt; 20) {\n                                    boardCtx.fillRect(\n                                        boardX * cellWidth + 1,\n                                        boardY * cellHeight + 1,\n                                        cellWidth - 2,\n                                        cellHeight - 2\n                                    );\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            drawGrid();\n        }\n\n        function drawNextPiece() {\n            \/\/ \u80cc\u666f\u3092\u30af\u30ea\u30a2\n            nextCtx.fillStyle = '#0f0f0f';\n            nextCtx.fillRect(0, 0, elements.nextPiece.width, elements.nextPiece.height);\n\n            if (gameState &amp;&amp; gameState.nextPiece) {\n                const piece = gameState.nextPiece;\n                const cellSize = 25; \/\/ \u30cd\u30af\u30b9\u30c8\u30d4\u30fc\u30b9\u7528\u306e\u30bb\u30eb\u30b5\u30a4\u30ba\n                const offsetX = (elements.nextPiece.width - cellSize * 4) \/ 2;\n                const offsetY = (elements.nextPiece.height - cellSize * 4) \/ 2;\n\n                nextCtx.fillStyle = getBlockColor(getTetrominoTypeNumber(piece.type));\n\n                for (let row = 0; row &lt; 4; row++) {\n                    for (let col = 0; col &lt; 4; col++) {\n                        if (piece.shape&#91;row] &amp;&amp; piece.shape&#91;row]&#91;col]) {\n                            nextCtx.fillRect(\n                                offsetX + col * cellSize + 1,\n                                offsetY + row * cellSize + 1,\n                                cellSize - 2,\n                                cellSize - 2\n                            );\n                        }\n                    }\n                }\n            }\n        }\n\n        function getBlockColor(typeNum) {\n            const colors = {\n                1: '#00ffff', \/\/ I - \u30b7\u30a2\u30f3\n                2: '#ffff00', \/\/ O - \u9ec4\u8272\n                3: '#800080', \/\/ T - \u7d2b\n                4: '#00ff00', \/\/ S - \u7dd1\n                5: '#ff0000', \/\/ Z - \u8d64\n                6: '#0000ff', \/\/ J - \u9752\n                7: '#ffa500'  \/\/ L - \u30aa\u30ec\u30f3\u30b8\n            };\n            return colors&#91;typeNum] || '#666';\n        }\n\n        function getTetrominoTypeNumber(type) {\n            const typeMap = { 'I': 1, 'O': 2, 'T': 3, 'S': 4, 'Z': 5, 'J': 6, 'L': 7 };\n            return typeMap&#91;type] || 1;\n        }\n\n        function updateButtonStates(gameRunning) {\n            elements.startBtn.disabled = gameRunning;\n            elements.pauseBtn.disabled = !gameRunning || (gameState &amp;&amp; gameState.isGameOver);\n\n            if (gameState &amp;&amp; gameState.isPaused) {\n                elements.pauseBtn.textContent = '\u25b6\ufe0f \u518d\u958b';\n            } else {\n                elements.pauseBtn.textContent = '\u23f8\ufe0f \u4e00\u6642\u505c\u6b62';\n            }\n        }\n\n        function showStatusMessage(message, type = 'info') {\n            elements.statusMessage.textContent = message;\n            elements.statusMessage.className = `status-message status-${type}`;\n            elements.statusMessage.style.display = 'block';\n\n            setTimeout(() =&gt; {\n                elements.statusMessage.style.display = 'none';\n            }, 3000);\n        }\n\n        \/\/ \u30da\u30fc\u30b8\u304c\u9589\u3058\u3089\u308c\u308b\u6642\u306e\u51e6\u7406\n        window.addEventListener('beforeunload', () =&gt; {\n            stopAutoDropSystem();\n        });\n\n        console.log('\u2705 \u30b9\u30af\u30ea\u30d7\u30c8\u8aad\u307f\u8fbc\u307f\u5b8c\u4e86');\n    &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"5\">\u5b9f\u884c<\/h2>\n\n\n\n<p>\u3053\u308c\u3067\u30c6\u30c8\u30ea\u30b9\u306e\u30b2\u30fc\u30e0\u304c\u5b8c\u6210\u3057\u307e\u3057\u305f\u3002<br>\u5b9f\u884c\u3057\u3066\u5b9f\u969b\u306b\u30b2\u30fc\u30e0\u304c\u51fa\u6765\u308b\u304b\u8a66\u3057\u3066\u307f\u307e\u3057\u3087\u3046\uff01\uff01<br>\u5b9f\u884c\u3057\u3066\u307f\u308b\u3068\u30a6\u30a7\u30d6\u30d6\u30e9\u30a6\u30b6\u304c\u7acb\u3061\u4e0a\u304c\u308a\u30c6\u30c8\u30ea\u30b9\u306e\u753b\u9762\u304c\u51fa\u3066\u304d\u307e\u3059\u3002<br>\u5b9f\u969b\u306b\u30d7\u30ec\u30a4\u3057\u3066\u307f\u308b\u3068\u554f\u984c\u306a\u304f\u30c6\u30c8\u30ea\u30b9\u3067\u904a\u3076\u3053\u3068\u304c\u51fa\u6765\u307e\u3057\u305f\u3002<br>\u3061\u306a\u307f\u306b\u4e00\u756a\u4e0a\u307e\u3067\u30d6\u30ed\u30c3\u30af\u304c\u884c\u304f\u3068\u30b2\u30fc\u30e0\u30aa\u30fc\u30d0\u30fc\u3068\u306a\u308a\u3001\u753b\u50cf\u306e\u3088\u3046\u306a\u8868\u8a18\u304c\u51fa\u3066\u30b9\u30b3\u30a2\u304c\u8868\u793a\u3055\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"728\" height=\"848\" src=\"https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-162540.png\" alt=\"\" class=\"wp-image-21989\" srcset=\"https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-162540.png 728w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-162540-258x300.png 258w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-162540-275x320.png 275w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-162540-549x640.png 549w\" sizes=\"auto, (max-width: 728px) 100vw, 728px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"694\" height=\"831\" src=\"https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163518.png\" alt=\"\" class=\"wp-image-21990\" srcset=\"https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163518.png 694w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163518-251x300.png 251w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163518-267x320.png 267w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163518-534x640.png 534w\" sizes=\"auto, (max-width: 694px) 100vw, 694px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"445\" height=\"244\" src=\"https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163613.png\" alt=\"\" class=\"wp-image-21991\" srcset=\"https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163613.png 445w, https:\/\/itport.cloud\/wp-content\/uploads\/2025\/08\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-08-18-163613-300x164.png 300w\" sizes=\"auto, (max-width: 445px) 100vw, 445px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"6\">\u307e\u3068\u3081<\/h2>\n\n\n\n<p>\u4eca\u56de\u306f\u30c6\u30c8\u30ea\u30b9\u3092\u4f5c\u6210\u3057\u3066\u307f\u307e\u3057\u305f\u3002<br>\u8a18\u8f09\u51fa\u6765\u3066\u3044\u307e\u305b\u3093\u304c\u3001\u9014\u4e2d\u3067\u306f\u5b9f\u884c\u3057\u3066\u3082\u30a8\u30e9\u30fc\u304c\u3067\u3066\u306a\u304b\u306a\u304b\u539f\u56e0\u304c\u5206\u304b\u3089\u305a\u3001Claude\u306b\u805e\u3044\u3066\u4fee\u6b63\u3057\u3066\u3082\u3089\u3063\u305f\u308a\u3001<br>\u4fee\u6b63\u3057\u3066\u3082\u3089\u3063\u3066\u3082\u3001\u3055\u3089\u306b\u5225\u306e\u30a8\u30e9\u30fc\u304c\u51fa\u305f\u308a\u3068\u306a\u304b\u306a\u304b\u5b8c\u6210\u305b\u305a\u306b\u82e6\u52b4\u3057\u307e\u3057\u305f\u3002<br>\u3057\u304b\u3057\u3001\u4f55\u3068\u304b\u5b8c\u6210\u307e\u3067\u3053\u304e\u3064\u3051\u3089\u308c\u305f\u306e\u3067\u826f\u304b\u3063\u305f\u3068\u601d\u3044\u307e\u3059\u3002<br>\u7686\u3055\u3093\u3082\u662f\u975e\u6a5f\u4f1a\u304c\u3042\u308c\u3070\u4f5c\u6210\u3057\u3066\u307f\u3066\u306f\u3044\u304b\u304c\u3067\u3057\u3087\u3046\u304b\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"\u76ee\u6b21 \u524d\u56de\u306e\u304a\u3055\u3089\u3044Controller\u5b9f\u88c5\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u6709\u52b9\u5316View\u5b9f\u88c5\u5b9f\u884c\u307e\u3068\u3081 \u524d\u56de\u306e\u304a\u3055\u3089\u3044 \u524d\u56de\u306fModel\u90e8\u5206\u306e\u4f5c\u6210\u3092\u3057\u307e\u3057\u305f\u3002\u5177\u4f53\u7684\u306b\u306f\u4ee5\u4e0b\u306e\u30af\u30e9\u30b9\u3068\u306a\u308a\u307e\u3059\u3002 1,Tetrimino.cs\u3000\u30c6\u30c8\u30ea\u30df\u30ce\uff08\u843d\u3061\u3066\u304f\u308b\u30d6\u30ed\u30c3\u30af\uff092,GameBoard.cs\u3000\u30b2\u30fc\u30e0\u76e4\u306e\u7ba1\u74063,TetrisGame.cs\u3000\u30b2\u30fc\u30e0\u5168\u4f53\u306e\u5236\u5fa1 \u4eca\u56de\u306fController\u3068View\u3092\u4f5c\u6210\u3057\u3066\u3044\u304d\u307e\u3059\u3002 Controller\u5b9f\u88c5 \u307e\u305a\u306f GameController\u3092\u5b9f\u88c5\u3057\u3066\u3044\u304d\u307e\u3059\u3002Controllers\u30d5\u30a9\u30eb\u30c0\u306b\u65b0\u3057\u3044\u30af\u30e9\u30b9\u3092\u4f5c\u6210\u3057\u3001\u4ee5\u4e0b\u306e\u30b3\u30fc\u30c9\u3092\u66f8\u304d\u307e\u3059\u3002 using Microsoft.AspNetCore.Mvc; using Tetris&hellip;","protected":false},"author":38,"featured_media":21992,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[180],"tags":[181],"class_list":{"0":"post-21960","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-c","8":"tag-season62"},"_links":{"self":[{"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/posts\/21960","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/itport.cloud\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=21960"}],"version-history":[{"count":6,"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/posts\/21960\/revisions"}],"predecessor-version":[{"id":22085,"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/posts\/21960\/revisions\/22085"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/itport.cloud\/index.php?rest_route=\/wp\/v2\/media\/21992"}],"wp:attachment":[{"href":"https:\/\/itport.cloud\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21960"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itport.cloud\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21960"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itport.cloud\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21960"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}