Skip to content

Commit

Permalink
Merge pull request #240 from wellFoundedDevelopers/hyunsoo/58week
Browse files Browse the repository at this point in the history
[전현수] - 양치기 꿍, 술래 잡기
  • Loading branch information
soopeach authored May 5, 2024
2 parents cb7b3bf + efb4f9d commit 3b3a7de
Show file tree
Hide file tree
Showing 4 changed files with 1,065 additions and 0 deletions.
220 changes: 220 additions & 0 deletions src/main/kotlin/hyunsoo/58week/술래 잡기.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
package hyunsoo.`58week`

import java.util.Stack
import kotlin.math.absoluteValue

/**
*
* <문제>
* [술래 잡기](https://www.codetree.ai/training-field/frequent-problems/problems/hide-and-seek/description?page=1&pageSize=20)
*
* - 아이디어
*
* - 트러블 슈팅
*
*/
class `전현수_술래_잡기` {

data class Position(val x: Int, val y: Int) {

operator fun plus(other: Position): Position {
return Position(x + other.x, y + other.y)
}

operator fun minus(other: Position): Position {
return Position(x - other.x, y - other.y)
}

operator fun times(cnt: Int): Position {
return Position(x * cnt, y * cnt)
}

fun diff(other: Position): Int {
return (this.x - other.x).absoluteValue + (this.y - other.y).absoluteValue
}
}

private data class Fugitive(val pos: Position, val orientation: FugitiveDirs)

private val fugitiveList = mutableListOf<Fugitive?>()

private val treeList = mutableListOf<Position>()

private val dirs = listOf(
Position(-1, 0),
Position(0, 1),
Position(1, 0),
Position(0, -1)
)

enum class FugitiveDirs(val dir: Position) {
UP(Position(-1, 0)),
DOWN(Position(1, 0)),
RIGHT(Position(0, 1)),
LEFT(Position(0, -1));

fun change() = when (this) {
UP -> DOWN
DOWN -> UP
LEFT -> RIGHT
else -> LEFT
}
}

fun solution() {

val (size, fugitiveCnt, treeCnt, turnCnt) = readLine()!!.split(" ").map { it.toInt() }
var totalScore = 0

var tagger = Position(size / 2, size / 2)
var taggerDir = dirs.first()
// 움직인 횟수
var taggerMoveCnt = 0
var criterionForCriterion = 0
var criterion = 1
var isForward = true

repeat(fugitiveCnt) {
val (x, y, dir) = readLine()!!.split(" ").map { it.toInt() }
fugitiveList.add(
Fugitive(
Position(x - 1, y - 1),
if (dir == 1) FugitiveDirs.RIGHT else FugitiveDirs.DOWN
)
)
}

repeat(treeCnt) {
readLine()!!.split(" ").map { it.toInt() }.apply {
treeList.add(Position(first() - 1, last() - 1))
}
}

repeat(turnCnt) { turnIndex ->

// 도망자 이동
fugitiveList.forEachIndexed { fugIndex, curFug ->

if (curFug == null) return@forEachIndexed

val diff = curFug.pos.diff(tagger)
if (4 <= diff) return@forEachIndexed

val nextPos = curFug.pos + curFug.orientation.dir

// 격자를 벗어나지 않는 경우
if (nextPos.x in 0 until size &&
nextPos.y in 0 until size
) {
// 다음 칸에 술래 여부 확인
if (nextPos == tagger) return@forEachIndexed

fugitiveList[fugIndex] = curFug.copy(pos = nextPos)
// 격자를 벗어나는 경우
} else {

val rotatedCurFug = curFug.copy(
orientation = curFug.orientation.change()
)

// 방향 전환 적용
fugitiveList[fugIndex] = rotatedCurFug

val nextPos = rotatedCurFug.pos + rotatedCurFug.orientation.dir

// 다음 칸에 술래 여부 확인
if (nextPos == tagger) return@forEachIndexed

fugitiveList[fugIndex] = rotatedCurFug.copy(pos = nextPos)

}
}

// 술래 이동
if (isForward) {
tagger += taggerDir
taggerMoveCnt++

// 기준치 만큼 움직였을 경우 방향 전환
if (taggerMoveCnt == criterion) {
taggerDir = dirs[(dirs.indexOf(taggerDir) + 1) % 4]
criterionForCriterion++
taggerMoveCnt = 0
}

// 1 1, 2 2, 3 3 이런식으로 움직일 수 있도록
if (criterionForCriterion == 2) {
criterion++
criterionForCriterion = 0
}

if (tagger == Position(0, 0)) {
isForward = false
taggerDir = dirs[2]
taggerMoveCnt = 0
}

} else {
tagger += taggerDir
taggerMoveCnt++

// 처음 역방향 탐색 시 5 5 5, 4 4 이런식으로 움직여야함.
if (tagger.x !in 0 until size ||
tagger.y !in 0 until size
) {
tagger -= taggerDir
taggerDir = dirs[(dirs.indexOf(taggerDir) + 3) % 4]
tagger += taggerDir
taggerMoveCnt = 1
criterion--
} else {
// 기준치 만큼 움직였을 경우 방향 전환
if (taggerMoveCnt == criterion) {
taggerDir = dirs[(dirs.indexOf(taggerDir) + 3) % 4]
criterionForCriterion++
taggerMoveCnt = 0
}

if (criterionForCriterion == 2) {
criterion--
criterionForCriterion = 0
}

if (tagger == Position(size / 2, size / 2)) {
isForward = true
taggerDir = dirs.first()
taggerMoveCnt = 0
criterion = 1
criterionForCriterion = 0
}
}

}

val caughtFugitive = Stack<Int>()
for (i in 0 until 3) {
val nextPos = tagger + (taggerDir * i)
if (nextPos in treeList) continue

fugitiveList.forEachIndexed { index, fug ->
if (fug?.pos == nextPos) caughtFugitive.add(index)
}
}

while (caughtFugitive.isNotEmpty()) {
val targetIndex = caughtFugitive.pop()
fugitiveList[targetIndex] = null
totalScore += turnIndex + 1
}

}

println(totalScore)
}


}

fun main() {
전현수_술래_잡기().solution()
}
122 changes: 122 additions & 0 deletions src/main/kotlin/hyunsoo/58week/양치기 꿍.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package hyunsoo.`58week`

import java.util.LinkedList
import java.util.Queue
import java.util.Stack

/**
*
* <문제>
* [양치기 꿍](https://www.acmicpc.net/problem/3187)
*
* - 아이디어
*
* - 트러블 슈팅
*
*/
class `전현수_양치기_꿍` {

private data class Position(val x: Int, val y: Int)

private val dirs = listOf(
Position(-1, 0),
Position(1, 0),
Position(0, 1),
Position(0, -1),
)

private val board = mutableListOf<MutableList<String>>()

fun solution() {

val (r, c) = readln().split(" ").map { it.toInt() }

val visited = Array(r) {
BooleanArray(c)
}

repeat(r) {
val row = readln().chunked(1) as MutableList
board.add(row)
}

for (i in 0 until r) {
for (j in 0 until c) {

val cur = board[i][j]
if (cur == WALL || cur == EMPTY) continue

val sheepStack = Stack<Position>()
val wolfStack = Stack<Position>()

val queue: Queue<Position> = LinkedList()
queue.add(Position(i, j))

investigate(queue, sheepStack, wolfStack, visited)

if (wolfStack.size == 0 || sheepStack.size == 0) continue

if (wolfStack.size < sheepStack.size) consume(wolfStack)
else consume(sheepStack)

}
}

val flattedBoard = board.flatten()
println(
"${flattedBoard.count { it == SHEEP }} ${flattedBoard.count { it == WOLF }}"
)
}

private fun investigate(
queue: Queue<Position>,
sheepStack: Stack<Position>,
wolfStack: Stack<Position>,
visited: Array<BooleanArray>,
) {
while (queue.isNotEmpty()) {

val curPos = queue.poll()
val curInfo = board[curPos.x][curPos.y]

if (visited[curPos.x][curPos.y]) continue
visited[curPos.x][curPos.y] = true

if (curInfo == WOLF) wolfStack.add(Position(curPos.x, curPos.y))
else if (curInfo == SHEEP) sheepStack.add(Position(curPos.x, curPos.y))

dirs.forEach { dir ->
val nx = curPos.x + dir.x
val ny = curPos.y + dir.y

if (nx !in 0 until board.size ||
ny !in 0 until board.first().size ||
board[nx][ny] == WALL ||
visited[nx][ny]
) return@forEach

queue.add(Position(nx, ny))
}
}
}

private fun consume(stack: Stack<Position>) {

while (stack.isNotEmpty()) {
val curPos = stack.pop()
board[curPos.x][curPos.y] = "."
}

}

companion object {
const val WALL = "#"
const val EMPTY = "."
const val WOLF = "v"
const val SHEEP = "k"
}
}

fun main() {
전현수_양치기_꿍().solution()
}
Loading

0 comments on commit 3b3a7de

Please sign in to comment.