문제 링크

배운 점

  • ||연산은 앞 부분의 계산이 TRUE가 나오면 뒷 부분 연산을 시행하지 않는다점을 체험하였다.
  • 변수를 명명할 때 헷갈리지 않도록 주의
  • kotlin은 제한시간 1초를 초과한다. 새로운 IR backend를 사용하면 통과할 것으로 예상된다.

Kotlin

package baekjoon.kotlin.p19235

private fun readNum() = readLine()!!.toInt()
private fun readNums() = readLine()!!.split(" ").map { it.toInt() }

private val gBoard = Array(6) { Array(4) { 0 } }
private val bBoard = Array(6) { Array(4) { 0 } }
private val gBlock = listOf(listOf(0 to 0), listOf(0 to 0, 0 to 1), listOf(0 to 0, 1 to 0))
private val bBlock = listOf(listOf(0 to 0), listOf(0 to 0, 1 to 0), listOf(0 to 0, 0 to 1))

private val d = arrayOf(-1 to 0, 0 to -1, 0 to 1)

fun main() {
    val N = readNum()
    var blockNum = 1

    fun moveIfFloat(): Boolean {
        // 떠 있는 블록을 바닥에 붙인다. 블록을 움직였으면 true를 반환
        fun dropTheBlock(board: Array<Array<Int>>): Boolean {
            var ret = false
            for (r in 4 downTo 0) for (c in 3 downTo 0) {
                if (board[r][c] == 0) continue
                if (board[r + 1][c] != 0) continue

                val blocks = mutableListOf(r to c)
                val curBlock = board[r][c]
                d.forEach {
                    if (r + it.first >= 0 && c + it.second >= 0 && c + it.second < 4 && curBlock == board[r + it.first][c + it.second])
                        blocks.add(r + it.first to c + it.second)
                }
                var isMovable = true
                while (isMovable) {
                    for (i in blocks.indices) {
                        if (blocks[i].first == 5) {
                            isMovable = false
                            break
                        }
                        val n = board[blocks[i].first + 1][blocks[i].second]
                        if (n == 0 || n == curBlock) {
                            blocks[i] = blocks[i].first + 1 to blocks[i].second
                        } else {
                            isMovable = false
                            break
                        }
                    }
                    if (isMovable) {
                        ret = true
                        blocks.forEach {
                            board[it.first - 1][it.second] = 0
                            board[it.first][it.second] = curBlock
                        }
                    }
                }
            }

            return ret
        }
        val g = dropTheBlock(gBoard)
        val b = dropTheBlock(bBoard)

        return g || b
    }

    fun cleanUpLines(): Int {
        // 파란 보드와 초록 보드의 라인을 이룬 부분을 제거한다. 제거 했으면 true를 반환
        fun removeLine(board: Array<Array<Int>>): Int {
            var ret = 0
            for (r in 2 until 6) {
                if (!board[r].contains(0)) {
                    for (c in 0 until 4) board[r][c] = 0
                    ret++
                }
            }
            return ret
        }

        var ret = 0
        do {
            ret += removeLine(gBoard) + removeLine(bBoard)
        } while (moveIfFloat())

        return ret
    }

    fun moveIfOverflow(): Boolean {
        // 쌓인 블록이 넘치면 가장 바닥 부분을 한 줄 제거한다. 제거했으면 true를 반환
        fun moveBoard(board: Array<Array<Int>>): Boolean {
            if (board[0].any { it != 0 }) {
                for (c in 0 until 4) {
                    board[4][c] = 0
                    board[5][c] = 0
                }
                return true
            } else if (board[1].any { it != 0 }) {
                for (c in 0 until 4) board[5][c] = 0
                return true
            }
            return false
        }
        val g = moveBoard(gBoard)
        val b = moveBoard(bBoard)
        return  g || b
    }

    fun pileBlock(t: Int, x: Int, y: Int) {
        // 블록을 쌓는다.
        gBlock[t - 1].forEach { gBoard[it.first][y + it.second] = blockNum }
        bBlock[t - 1].forEach { bBoard[it.first][x + it.second] = blockNum }
        moveIfFloat()
    }

    var ret = 0

    repeat(N) {
        val (t, x, y) = readNums()

        pileBlock(t, x, y)
        ret += cleanUpLines()
        if (moveIfOverflow())
            moveIfFloat()
        blockNum++
    }

    println(ret)
    println(gBoard.sumBy { r -> r.sumOf { (if (it == 0) 0 else 1).toInt() } } +
            bBoard.sumBy { r -> r.sumOf { (if (it == 0) 0 else 1).toInt() } })

    println()
    gBoard.forEach { r ->
        r.forEach {
            print("$it ")
        }
        println()
    }
    println()
    bBoard.forEach { r ->
        r.forEach {
            print("$it ")
        }
        println()
    }
}

Java

package baekjoon.java.p19235;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    private static int N;
    private static int blockNum;
    private static int[][] gBoard = new int[6][4];
    private static int[][] bBoard = new int[6][4];
    private static int[][] d = {{-1, 0}, {0, -1}, {0, 1}};

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        N = Integer.parseInt(br.readLine());
        int ret = 0;
        while (N-- != 0) {
            blockNum++;
            StringTokenizer st = new StringTokenizer(br.readLine(), " ");
            int t, x, y;
            t = Integer.parseInt(st.nextToken());
            x = Integer.parseInt(st.nextToken());
            y = Integer.parseInt(st.nextToken());

            pileBlock(t, x, y);
            ret += cleanUpLines();
            if (moveIfOverflow())
                moveIfFloat();
        }
        bw.write(Integer.toString(ret));
        int cnt = 0;
        for(int r = 0; r < 6; r++) for(int c = 0; c < 4; c++) {
            if(gBoard[r][c] != 0) cnt++;
            if(bBoard[r][c] != 0) cnt++;
        }
        bw.newLine();
        bw.write(Integer.toString(cnt));
        bw.newLine();
        bw.flush();

        /*for(int[] r : gBoard) {
            for (int v : r) {
                System.out.print(Integer.toString(v) + " ");
            }
            System.out.println();
        }
        System.out.println();
        for(int[] r : bBoard) {
            for (int v : r) {
                System.out.print(Integer.toString(v) + " ");
            }
            System.out.println();
        }*/
    }

    private static boolean moveIfFloat() {
        boolean g = dropTheBlock(gBoard);
        boolean b = dropTheBlock(bBoard);
        return g || b;
    }

    public static boolean isInside(int r, int c) {
        return r < 6 && r >= 0 && c < 4 && c >= 0;
    }

    private static boolean dropTheBlock(int[][] board) {
        boolean ret = false;
        for (int r = 4; r >= 0; r--) {
            for (int c = 3; c >= 0; c--) {
                if (board[r][c] == 0) continue;
                if (board[r + 1][c] != 0) continue;

                ArrayList<Pair> blocks = new ArrayList<>();
                int boardNum = board[r][c];
                blocks.add(new Pair(r, c));
                for (int[] mv : d) {
                    int nr = r + mv[0], nc = c + mv[1];
                    if (isInside(nr, nc) && board[nr][nc] == boardNum)
                        blocks.add(new Pair(nr, nc));
                }
                int dist = 99;
                for (Pair block : blocks) {
                    int cnt = 0;
                    for (int i = block.f + 1; i < 6; i++) {
                        if (board[i][block.s] != 0 && (board[i][block.s] != boardNum))
                            break;
                        cnt++;
                    }
                    dist = Integer.min(dist, cnt);
                }
                if (dist != 0) {
                    ret = true;
                }
                for (Pair block : blocks) {
                    board[block.f][block.s] = 0;
                }
                for(Pair block : blocks) {
                    board[block.f + dist][block.s] = boardNum;
                }
            }
        }
        return ret;
    }

    private static boolean moveIfOverflow() {
        int gMv = getOverflowed(gBoard);
        int bMv = getOverflowed(bBoard);

        for (int r = 6 - gMv; r < 6; r++)
            for (int c = 0; c < 4; c++)
                gBoard[r][c] = 0;
        for (int r = 6 - bMv; r < 6; r++)
            for (int c = 0; c < 4; c++)
                bBoard[r][c] = 0;

        return gMv != 0 || bMv != 0;
    }

    private static int getOverflowed(int[][] board) {
        for (int r = 0; r < 2; r++) {
            for (int c = 0; c < 4; c++) {
                if (board[r][c] != 0) {
                    return 2 - r;
                }
            }
        }
        return 0;
    }

    private static int cleanUpLines() {
        int ret = 0;

        do {
            for (int r = 2; r < 6; r++) {
                int gCnt = 0, bCnt = 0;
                for (int c = 0; c < 4; c++) {
                    if (gBoard[r][c] != 0) gCnt++;
                    if (bBoard[r][c] != 0) bCnt++;
                }
                if (gCnt == 4) {
                    ret++;
                    for (int c = 0; c < 4; c++) gBoard[r][c] = 0;
                }
                if (bCnt == 4) {
                    ret++;
                    for (int c = 0; c < 4; c++) bBoard[r][c] = 0;
                }
            }
        } while (moveIfFloat());

        return ret;
    }

    private static void pileBlock(int t, int x, int y) {
        switch (t) {
            case 2:
                gBoard[0][y + 1] = blockNum;
                bBoard[1][x] = blockNum;
                break;
            case 3:
                gBoard[1][y] = blockNum;
                bBoard[0][x + 1] = blockNum;
                break;
        }
        gBoard[0][y] = blockNum;
        bBoard[0][x] = blockNum;
    }

    private static class Pair {
        public int f;
        public int s;

        public Pair(int f, int s) {
            this.f = f;
            this.s = s;
        }
    }
}

댓글남기기