import arsd.simpledisplay; /+ It is an 8x8 grid gives you 3 random pieces at a time you must place all three on the grid before getting a new set complete rows or columns will clear the line +/ immutable string[] pieceOptions = [ "xx", "xxx", "xxxx", "xxxxx", "x xx x", ".x xx .x", ".x. xxx", "xxx .x.", "x x", "x x x", "x x x x", "x x x x x", "xxx xxx xxx", "xxx x x", "xxx ..x ..x", ]; class BlockPuzzle { private int[8][8] grid; private static struct Piece { this (string arg) immutable { int lineCount = 0; int maxLineWidth; int lineWidth; bool onNewLine = true; foreach(ch; arg) { if(ch == '\r' || ch == '\t') continue; if(ch == '\n') onNewLine = true; else if(ch == ' ') continue; else { if(onNewLine) { lineCount++; if(lineWidth > maxLineWidth) maxLineWidth = lineWidth; lineWidth = 0; onNewLine = false; } lineWidth++; } } if(lineWidth > maxLineWidth) maxLineWidth = lineWidth; this.width = maxLineWidth; this.height = lineCount; int[] shape; shape.length = width * height; onNewLine = false; lineWidth = 0; int idx; foreach(ch; arg) { if(ch == '\r' || ch == '\t') continue; if(ch == '\n') onNewLine = true; else if(ch == ' ') continue; else { if(onNewLine) { foreach(i; lineWidth .. maxLineWidth) shape[idx++] = 0; lineWidth = 0; onNewLine = false; } shape[idx++] = ch == '.' ? 0 : 1; lineWidth++; } } this.shape = cast(immutable int[]) shape; /+ int i; import std.stdio; writeln("\n", width, " ", height); foreach(y; 0..height) { foreach(x; 0..width) std.stdio.write(shape[i++] ? "X": "."); writeln; } +/ } int width; int height; int[] shape; } immutable Piece*[] pieceOptions; this() { immutable(Piece*)[] po; po.reserve(.pieceOptions.length); foreach(option; .pieceOptions) po ~= new immutable Piece(option); this.pieceOptions = po; loadNewPieces(); } enum size = 32; immutable Color[] colors = [Color.black, Color.blue]; private int selectedPiece; private Point selectionWhere; void changeSelectedPiece() { foreach(i; 0 .. currentPieces.length) { selectedPiece++; if(selectedPiece == 3) selectedPiece = 0; if(currentPieces[selectedPiece] !is null) return; } selectedPiece = -1; } private immutable(Piece)*[3] currentPieces; void loadNewPieces() { // FIXME import std.random; foreach(ref piece; currentPieces) piece = pieceOptions[uniform(0, pieceOptions.length)]; changeSelectedPiece(); } void moveSelectionBy(Point howMuch) { selectionWhere = selectionWhere + howMuch; } void placeSelection() { if(!isLegalMove(currentPieces[selectedPiece], selectionWhere)) return; auto p = currentPieces[selectedPiece]; foreach(y; 0 .. p.height) foreach(x; 0 .. p.width) if(p.shape[y * p.width + x]) grid[selectionWhere.y + y][selectionWhere.x + x] = p.shape[y * p.width + x]; int[8] completedRows; int[8] completedColumns; foreach(column; 0 .. 8) foreach(row; 0 .. 8) { if(grid[row][column]) { completedRows[row]++; completedColumns[column]++; } } foreach(row, cr; completedRows) if(cr == 8) foreach(col; 0 .. 8) grid[row][col] = 0; foreach(col, cc; completedColumns) if(cc == 8) foreach(row; 0 .. 8) grid[row][col] = 0; currentPieces[selectedPiece] = null; changeSelectedPiece(); if(selectedPiece == -1) loadNewPieces(); } bool isLegalMove(immutable Piece* piece, Point where) { if(where.x < 0 || where.y < 0) return false; foreach(int y; 0 .. piece.height) foreach(int x; 0 .. piece.width) { if(piece.shape[y * piece.width + x] == 0) continue; if(where.y + y >= 8) return false; if(where.x + x >= 8) return false; if(grid[where.y + y][where.x + x]) return false; } return true; } bool hasLegalMove(immutable Piece* piece) { foreach(int y, row; grid) foreach(int x, cell; row) if(isLegalMove(piece, Point(x, y))) return true; return false; } // sdpy specific void drawInto(ref ScreenPainter painter) { drawInto(painter, selectedPiece, selectionWhere); } private void drawInto(ref ScreenPainter painter, int selectedPiece, Point where) { painter.fillColor = Color.black; painter.outlineColor = Color.black; painter.drawRectangle(Point(0, 0), Size(512, 512)); painter.outlineColor = Color.white; foreach(int y, row; grid) foreach(int x, cell; row) { painter.fillColor = colors[cell]; painter.drawRectangle(Point(x * size, y * size), Size(size, size)); } if(selectedPiece != -1) { // FIXME drawPieceInto(painter, currentPieces[selectedPiece], selectionWhere * size, Color.yellow); } foreach(int idx, piece; currentPieces) { if(piece is null) continue; auto color = hasLegalMove(piece) ? Color.red : Color.gray; drawPieceInto(painter, piece, Point(idx * size*6, size*8 + size), color); } } void drawPieceInto(ref ScreenPainter painter, immutable Piece* piece, Point whereOnScreen, Color color) { painter.fillColor = color; foreach(int y; 0 .. piece.height) foreach(int x; 0 .. piece.width) if(piece.shape[y * piece.width + x]) painter.drawRectangle(whereOnScreen + Point(size*x, size*y), Size(size, size)); } } void main() { auto puzzle = new BlockPuzzle(); auto window = new SimpleWindow(512, 512); { auto painter = window.draw; puzzle.drawInto(painter); } window.eventLoop(0, (KeyEvent ke) { if(!ke.pressed) return; switch(ke.key) { case Key.Tab: puzzle.changeSelectedPiece(); break; case Key.Left: puzzle.moveSelectionBy(Point(-1, 0)); break; case Key.Right: puzzle.moveSelectionBy(Point(1, 0)); break; case Key.Up: puzzle.moveSelectionBy(Point(0, -1)); break; case Key.Down: puzzle.moveSelectionBy(Point(0, 1)); break; case Key.Space: puzzle.placeSelection(); break; default: } auto painter = window.draw; puzzle.drawInto(painter); }); }