PC/UVa ID : 110107/10196

개요

체스판에서 킹이 상대방의 수에 의해서 잡힐 수 있다면, 체크 상태를 알려 주는 일을 하는 것이다. 체스를 할 줄 모르면 뭐, 체스 룰부터 아는게 좋다. 나같은 경우 장기 룰을 알고 있기 때문에 장기와 빗대서 말하겠다.

폰(p) : 한번에 앞으로 한칸 씩 앞으로 갈 수 있으나, 상대 패를 먹을 때는 앞쪽 대각선 1칸 범위에서만 막을 수 있다. 마지막 폰은 뒤로 갈 수 없으며, 뒤로 가서 먹을 수도 없다.

나이트(n) : 장기의 馬 같은 움직임을 가진 녀석인데, 주변 장애물에 상관없이 공격 할 수 있다.

비숍(b) : 대각선 방향으로 거리 제약 없이 이동하면서 상대 패를 먹을 수 있다.

록(r) : 장기의 車 와 같은 움직임을 가진 녀석이다.

퀸(q) : 비숍과 록의 움직임을 다 가지고 있다.

킹(k) : 장기의 王과 같은 움직임을 가지고 있으나, 활동 범위는 넓다.

유의사항
폰의 움직임이 앞쪽만 움직일 수 있는데, 체스의 경우, 흰패와 검은패가 있다. 검은패는 위쪽에서 시작하여, 아래쪽으로 움직이는 방향이다. 즉, ↓, 흰패의 경우 검은패와 반대 방향을 가지고 있다.

보다 자세히 알고 싶다면 다음 링크를 봐라.

http://ko.wikipedia.org/wiki/%EC%B2%B4%EC%8A%A4

입력

위의 링크의 사진을 보면 알 수 있듯이 가로(8) X 세로(8) 을 가지고 있다. 패가 없는 자리는 "." 으로 표현하고, 패가 있는 자리는 위에서 말한 p, n, b, r, q, k 로 표현하고, 검은패가 소문자, 흰 패가 대문자이다.


출력

각 판의 배치에 따라, 체크를 당하는 쪽의 색을 기준으로 간단한 문구를 말하면 된다.
예)
white king is in check.
black king is in check.
no king is in check.

등..
문제를 보다 자세히 보려면, http://online-judge.uva.es/p/v101/10196.html 참고 하길 바란다.

생각해 봐야 할 주제
1. 흰/검은 색에 따른 폰의 움직임
2. 장애물이 있을 경우, 각 패의 움직임, 나이트는 생각할 필요가 없음

문제 푸는 중~ 이런게 바로 재미있는거~

코드

  1. 입력은 그냥 배열 입력으로 처리 했다.
  2. 방향성이란 개념을 넣었고, 폰의 경우 방향성을 거꾸로 만들어 사용 했음
  3. 폰의 이동만을 위한 수가 있고, 공격 할 수 있는 수가 따로 있어서, 기물의 이동시 "이동(M), 공격(A)" 속성을 넣어주어, 이동과 공격을 처리 할 수 있게 했다.


posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요

  1. Favicon of https://www.ikpil.com 농사를 짓는 게임 프로그래머 최익필 2009.10.28 07:05 신고  Addr  Edit/Del  Reply

    문제를 풀고 답지를 봐보니 나와 다른 점을 찾았다.

    나의 경우
    1. 각각의 체스 말을 직접 이동 시켜, 이동 경로를 뽑아 냄
    2. 공격 할 수 있는 상대 위치도 뽑아냅(각 체스 말 마다)

    2번을 뽑은 것 중 왕이 있는지 찾아서, 결론을 내는 구조임


    책의 풀이의 경우
    1. 왕의 좌표를 구함
    2. 상대 말들에 접근하여 왕의 좌표를 먹을 수 있는지 체크 함

    비슷한 로직
    1. 판을 180도 돌린다든가 뭐 그런건 벡터를 거꾸로 한 내 경우와 개념상 똑같음

  2. Favicon of https://www.ikpil.com 농사를 짓는 게임 프로그래머 최익필 2009.10.28 08:36 신고  Addr  Edit/Del  Reply

    추가.
    루아엔 continue, switch ~ case 가 없다. ..고의적으로 없앤건가 아니면 아직 구현 중인가?
    아니면 내가 너무 의존적으로 코드를 짜고 있는 건가?

  3. Favicon of https://www.ikpil.com 농사를 짓는 게임 프로그래머 최익필 2009.10.29 22:02 신고  Addr  Edit/Del  Reply

    리펙토링 중 ...
    중복 코드 삭제와 모듈화

  4. Favicon of https://www.ikpil.com 농사를 짓는 게임 프로그래머 최익필 2009.10.31 12:17 신고  Addr  Edit/Del  Reply

    MovingTable =
    {
    { x_ = -2, y_ = 2 }, { x_ = -1, y_ = 2 }, { x_ = 0, y_ = 2 }, { x_ = 1, y_ = 2 }, { x_ = 2, y_ = 2 },
    { x_ = -2, y_ = 1 }, { x_ = -1, y_ = 1 }, { x_ = 0, y_ = 1 }, { x_ = 1, y_ = 1 }, { x_ = 2, y_ = 1 },
    { x_ = -2, y_ = 0 }, { x_ = -1, y_ = 0 }, { x_ = 0, y_ = 0 }, { x_ = 1, y_ = 0 }, { x_ = 2, y_ = 0 },
    { x_ = -2, y_ = -1 }, { x_ = -1, y_ = -1 }, { x_ = 0, y_ = -1 }, { x_ = 1, y_ = -1 }, { x_ = 2, y_ = -1 },
    { x_ = -2, y_ = -2 }, { x_ = -1, y_ = -1 }, { x_ = 0, y_ = -1 }, { x_ = 1, y_ = -2 }, { x_ = 2, y_ = -2 },
    }


    CENTER = 13
    UP = -5
    LEFT = -1
    DOWN = 5
    RIGHT = 1

    MovesOfBishop = {
    UP + LEFT,
    UP + RIGHT,
    DOWN + LEFT,
    DOWN + RIGHT
    }

    MovesOfRook = {
    UP,
    LEFT,
    DOWN,
    RIGHT
    }

    MovesOfQueen = {
    UP + LEFT,
    UP + RIGHT,
    DOWN + LEFT,
    DOWN + RIGHT,
    UP, LEFT, DOWN, RIGHT
    }

    MovesOfKing = {
    UP + LEFT,
    UP + RIGHT,
    DOWN + LEFT,
    DOWN + RIGHT,
    UP, LEFT, DOWN, RIGHT
    }
    MovesOfNight = {
    2 * UP + LEFT,
    2 * UP + RIGHT,
    2 * LEFT + UP,
    2 * LEFT + DOWN,
    2 * DOWN + LEFT,
    2 * DOWN + RIGHT,
    2 * RIGHT + UP,
    2 * RIGHT + DOWN
    }

    MovesOfPawn = {
    UP
    }

    MovesOfVessel = { }
    MovesOfVessel['B'] = MovesOfBishop
    MovesOfVessel['R'] = MovesOfRook
    MovesOfVessel['Q'] = MovesOfQueen
    MovesOfVessel['K'] = MovesOfKing
    MovesOfVessel['N'] = MovesOfNight
    MovesOfVessel['P'] = MovesOfPawn

    CountOfMove = { }
    CountOfMove['B'] = 8
    CountOfMove['R'] = 8
    CountOfMove['Q'] = 8
    CountOfMove['K'] = 1
    CountOfMove['N'] = 1
    CountOfMove['P'] = 1

    function CreateUnit( VesselType )
    Unit = { }

    if '.' == VesselType then
    Unit.Who_ = 0
    return Unit
    elseif 'a' <= VesselType and 'z' >= VesselType then
    Unit.Who_ = 1
    else
    Unit.Who_ = -1
    end

    Unit.ToBeMovedCoordinates_ = { }
    Unit.ToBeAttackCoordinates_ = { }

    Unit.VesselType_ = VesselType

    return Unit
    end


    -- 이 함수는 기물의 이동을 처리하는 것 이다.
    -- 월드 좌표
    -- 유닛
    -- 시작점,
    -- 정규화된 벡터
    -- 반복 제한 횟수
    -- 이동 될 수 있는 좌표
    function ProcessOfVessel( ChessPane, Unit, StartPoint, MovingState, NormalVec, LoopCount)
    -- 루프카운터를 체크 하여 0이라면 끝낸다.
    if 0 == LoopCount then
    return
    end

    -- 벡터를 이용하여, 시작점에서 이동 될 수 있는 점을 구한다.
    ToBeMovedPoint = {}
    ToBeMovedPoint.x_ = StartPoint.x_ + NormalVec.x_
    ToBeMovedPoint.y_ = StartPoint.y_ + NormalVec.y_

    -- 범위 체크, 이동 범위, x,y 중 1보다 작다면 그냥 끝낸다.
    if 1 > ToBeMovedPoint.x_ or 1 > ToBeMovedPoint.y_ then
    return
    end

    -- 범위 체크, 이동 범위, X,Y 중 8보다 크다면 그냥 끝낸다.
    if 8 < ToBeMovedPoint.x_ or 8 < ToBeMovedPoint.y_ then
    return
    end

    -- 월드 좌표계에서 해당 위치가 어떤 상태인지 가져 온다.
    TheUnitOfPane = ChessPane[ToBeMovedPoint.y_][ToBeMovedPoint.x_]

    -- 인자로 들어온 유닛의 이동 가능 계산
    -- 인자로 들어온 유닛의 공격 가능 계산

    -- 아무도 없을 경우, 이동 할 수 있으므로, 구한 값을 저장하고 다시 자신을 호출한다.
    if 0 == TheUnitOfPane.Who_ and string.find(MovingState, "M") then
    Unit.ToBeMovedCoordinates_[#Unit.ToBeMovedCoordinates_ + 1] = ToBeMovedPoint
    return MoveEngine( ChessPane, Unit, ToBeMovedPoint, MovingState, NormalVec, LoopCount - 1 )

    -- 나와 다른 편일 경우, 이동과 공격을 함께 하는 유닛일 경우
    elseif 0 ~= TheUnitOfPane.Who_ and Unit.Who_ ~= TheUnitOfPane.Who_ and string.find(MovingState, "A") then
    Unit.ToBeAttackCoordinates_[#Unit.ToBeAttackCoordinates_ + 1] = ToBeMovedPoint
    return
    end
    -- 나와 다른 편일 경우, 공격을 하지 않는 유닛일 경우
    -- 나와 같은 편일 경우
    -- 위의 두 경우에 그냥 리턴한다.

    return
    end

    function MoveEngine( ChessPane, Unit, StartPoint, MovingState, NormalVec, LoopCount)
    end

    function AttackEngin( ChessPane, Unit, StartPoint, MovingState, NormalVec, LoopCount)
    end

    -- Seed에 의하여 노멀벡터의 방향을 반대로 바꾸거나 안바꾼다.
    function TransformNormalVec( Seed, NormalVec )
    TempVec = {}
    TempVec.x_ = NormalVec.x_ * Seed
    TempVec.y_ = NormalVec.y_ * Seed

    return TempVec
    end


    -- 체크판을 읽고, 왕이 잡힐 수 있는 상황인지 체크 한다.
    function CheckTheCheck( ChessPane )

    -- 각 유닛들을 생성하여 배치 시킨다.
    for y,ElementOfPane in ipairs(ChessPane) do
    for x, Vessel in ipairs(ElementOfPane) do
    ChessPane[y][x] = CreateUnit( Vessel )
    end
    end

    -- 각 유닛들을 얻어오고, 기물의 예상 범위를 움직여 보면서
    -- 1. 이동할 수 있는 지점들,
    -- 2. 상대 기물을 파괴할 수 있는 지점
    -- 1번과 2번을 조사한다.
    for y, ElementOfPane in ipairs(ChessPane) do
    for x, Unit in ipairs(ElementOfPane) do

    -- 어떤 유닛이고, 시작점이 어디인지 쓰기 편하게 받아 둔다.
    StartPoint = {x_ = x, y_ = y }

    if 0 ~= Unit.Who_ then
    VesselType = string.upper( Unit.VesselType_ )
    Moves = MovesOfVessel[VesselType]

    for i, MovingKey in ipairs( Moves ) do
    MovingKey = CENTER + MovingKey
    Moving = MovingTable[MovingKey]
    MoveEngine( ChessPane, Unit, StartPoint, "MA", TransformNormalVec(Unit.Who_, Moving), CountOfMove[VesselType] )
    end
    end
    end
    end

    AttackedKings = {}
    -- 이제 왕이 잡혔는지 체크 한다.
    for y, ElementOfPane in ipairs(ChessPane) do
    for x, Unit in ipairs(ElementOfPane) do

    -- 체스 판에 말이 있을 경우에만 돌아 간다.
    if 0 ~= Unit.Who_ then
    for i, AttackPoint in ipairs(Unit.ToBeAttackCoordinates_) do
    ToBeAttackedUnit = ChessPane[AttackPoint.y_][AttackPoint.x_]

    -- 공격 당하는 유닛이 킹일 경우
    if 'K' == string.upper(ToBeAttackedUnit.VesselType_) then
    -- 그 값을 저장해 둔다. 왜냐하면 모든 경우에 대해서 체크하기 위해서이다.
    -- 1. white 킹만 잡혔을 경우
    -- 2. black 킹만 잡혔을 경우
    -- 3. 아무 킹도 안잡혔을 경우
    -- 4. 두 킹 모두 잡혔을 경우
    AttackedKings[#AttackedKings + 1] = ToBeAttackedUnit
    end
    end
    end
    end
    end

    return AttackedKings
    end



    -- 흐름
    function main()
    -- 소문자가 흑, 위에서 아래로 공격
    -- 대문자가 백, 아래에서 위로 공격
    -- 1, 1 ~ 8, 8 로 시작 된다.
    ChessPane =
    {-- 1 2 3 4 5 6 7 8
    {'.', '.', 'k', '.', '.', '.', '.', '.'}, -- 1
    {'p', 'p', 'p', 'B', 'p', 'p', 'p', 'p'}, -- 2
    {'.', '.', '.', '.', '.', '.', '.', '.'}, -- 3
    {'.', 'R', '.', 'N', '.', '.', '.', '.'}, -- 4
    {'.', '.', '.', '.', '.', '.', '.', '.'}, -- 5
    {'.', '.', 'q', '.', '.', '.', '.', '.'}, -- 6
    {'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'}, -- 7
    {'K', '.', 'n', '.', '.', '.', '.', '.'} -- 8
    }

    -- 보기 좋게 출력
    for y, ElementOfPane in ipairs( ChessPane ) do
    OutLine = ""
    for x, Vessel in ipairs( ElementOfPane ) do
    OutLine = OutLine .. " " .. Vessel
    end
    print(OutLine)
    end

    -- 공격 당한 왕들을 받아 온다.
    AttackedKings = CheckTheCheck( ChessPane )

    -- 아무도 안잡혔을 경우
    if 0 == #AttackedKings then
    print("no king is in check.")

    -- 한쪽만 잡혔을 경우
    elseif 1 == #AttackedKings then
    King = AttackedKings[1]
    if 1 == King.Who_ then
    print("black(k) king is in check.")
    else
    print("while(K) king is in check.")
    end

    -- 두쪽 모두 잡혔을 경우
    elseif 2 == #AttackedKings then
    print("input error.")
    end
    end

    main()