SQLer 生島勘富 のブログ

RDB・SQLの話題を中心に情報発信をしています。

CODE VS 2.1 をSQLでやるとどうなる5

 前回の続きです。今回は、パックを投下するところまでを作ります。

 作るのは http://codevswc.jp/jpn/rule.html これです。データは、与えられるInputのサンプルとします。

 是非、ルールをよく読んで、「自分なら SQL でこういう方針で作る」
 「Javaなら、.Netなら、Rubyなら…… こういう方針で作る」

 と想像しながら読んでください。

 プログラムを作るよりも解説の方がはるかに難しい……。だんだん手抜きになってきていますがご容赦。

Turnテーブル(シミュレーション用)から全通りのパックを投下する

 前回作ったTurnテーブル(シミュレーション用)から、1つ目のパックが取り得る全通りのパターンで投下します。

 まず、現在、盤面に残っているブロック(現状は空)に、新しい SimulationID 次のターンにインサートします。

INSERT INTO Board
	(GameID, SimulationID, Turn, Row, Col, Num) 
SELECT 
	t.GameID
	, t.SimulationID
	, t.Turn 
	, b.Row
	, b.Col
	, b.Num
FROM
	Turn t
	LEFT JOIN board b
		ON t.GameID = b.GameID
		AND 0 = b.SimulationID -- 採用したパターン
		AND t.Turn = b.Turn -1
WHERE
	t.GameID = 0
	AND t.Turn = 1;

 続いて、パックデータを投下します
 尚、上のSQLのSELECT部分と、下のSQLのSELECT部分を、UNION ALLで繋いで1回にしても同じです。

INSERT INTO Board
	(GameID, SimulationID, Turn, Row, Col, Num) 
SELECT 
	tp.GameID
	, tp.SimulationID
	, tp.Turn
	, ISNULL(b.MaxRow, -1) -- ゼロオリジンなのでブロックがないときは-1
		+ RANK() OVER(PARTITION BY tp.SimulationID, tp.tCol ORDER BY tp.tRow)
	, tp.tCol
	, tp.Num
FROM
	(SELECT 
		t.GameID, t.Turn, t.SimulationID, t.Rot
		, dbo.ChangeRow(t.Rot, p.Row, p.Col, 4) AS tRow -- 回転後のRow
		, dbo.ChangeCol(t.Rot, p.Row, p.Col, 4) + t.XPos 
				AS tCol   -- 回転後落とす位置のCol  
		, p.Num
		FROM 
			Turn t
			INNER JOIN Pack p --参照されるPackテーブル
				ON t.GameID = p.GameID
				AND t.Turn = p.Turn + 1 -- Turnテーブルのターンはカウントアップ済み
		WHERE
			t.Turn = 1
	) AS tp
	LEFT JOIN (
			SELECT MAX(Row) As MaxRow, Col 
			FROM  Board 
			WHERE Turn = 0 -- コピー元を観た方が効率的
			GROUP BY Col) As b
		ON tp.tCol = b.Col
;

-- 確認 xx に1〜52までの数字を入れて、パックを回転させて
-- 狙った位置に投下できているか確認しましょう。
SELECT * FROM DispBoard10(0, xx, 1, 0)
ORDER BY Row DESC;