Dictionary 와 Circular Linked List 응용하기

EenSung Kim·2023년 11월 29일
0

스위프트 공부

목록 보기
1/6

오늘은 아주 간단한 차원에서 Swift 의 Dictionary 와 이를 바탕으로 생성 가능한 간단한 Circular Linked List 에 대해서 이야기를 해보려고 합니다.

Dictionary

이제 막 스위프트를 배워가는 입장이지만 코드를 작성하다 보면 참 편하다는 느낌을 받을 때가 많은데요. 딕셔너리를 활용하는 것도 그 중에 한가지가 아닌가 합니다.

스위프트의 딕셔너리는 정해진 순서 없이, key 와 여기에 대응하는 value 를 갖는 여러 값의 collection 이라고 할 수 있습니다. 키와 값을 갖는다는 점에서는 자바스크립트의 객체와도 비슷한 것 같지만, 키와 값은 각각 정해진 타입을 준수해야 하죠.

let dictionary: [ String : String ] = [
    "강아지" : "멍멍",
    "고양이" : "야옹야옹",
    "병아리" : "짹짹"
]

[] 로 감싸준다는 점을 제외하면 특별한 점이 있을까 싶은데요. 다음 예시를 보면 저처럼 자바스크립트에 익숙한 사람에게는 다소 생소한 활용이 나타납니다.

let anotherDictionary: [ Bool : Int ] = [
    true : 1,
    false : 2,
]

위 예시에서 볼 수 있듯이 스위프트의 딕셔너리는 키와 값으로 여러 다른 타입을 수용할 수도 있습니다. 그래서 자바스크립트에서라면 불가능했을 Bool 타입을 키로 활용할 수가 있죠.

이를 응용하면 다음 예시에서처럼 직접 열거형을 정의해주고 이를 딕셔너리에 활용하는 것도 얼마든지 가능합니다.

enum Status {
    case hp, mp, sp
}

let status: [ Status : Int ] = [
    .hp : 100,
    .mp : 50,
    .sp : 10
]

print(status[.hp]!) // 100 을 출력

Status 라는 열거형을 선언해 주었습니다. 그리고 이를 딕셔너리의 key 로 활용하고 있죠. 그러면 우리는 print()를 통해 확인할 수 있는 것처럼 열거형의 case 를 key 로 활용해서 그 값에 접근이 가능합니다.

오늘 다루려고 하는 내용에서는 이정도면 충분하기 때문에 딕셔너리를 더 깊게 이해하고 싶으시다면 swift.org 에서 제공하는 Dictionaries 문서를 확인해 보시면 좋을 것 같습니다. 그러면 다음으로 넘어가 볼께요.


Circular Linked List

위키피디아의 Linked list 문서를 보시면 링크드 리스트에 대해 간략하게나마 이해를 해볼 수 있습니다. 저도 깊이 이해하고 있는 건 아니라서 너무 딥하게 들어가진 않으려고 해요. 다만 오늘의 글에서는 링크드 리스트는 노드로 구성되어 있고, 각각의 노드는 그 다음 노드와 링크로 연결되어 있다는 점만 이해하면 됩니다.

그리고 순환 링크드 리스트는 링크드 리스트가 하나의 원을 이루는 구조를 의미합니다. geeksforgeeks.org 에서 제공하는 Circular Linked List 문서의 이미지가 잘 설명해 주고 있는데요. 리스트 안의 모든 노드들이 빠짐 없이 대응하는 노드와 연결되어 있죠.


가위바위보에 응용하기

순환 링크드 리스트나 링크드 리스트라는 자료 구조가 그 자체로 갖는 특징과 장점이 있겠지만, 오늘은 스위프트의 딕셔너리와 순환 링크드 리스트를 접목하여 재미있는 코드를 하나 살펴볼까 합니다. 바로 가위바위보의 승리 로직을 계산하기 위해 순환 링크드 리스트를 딕셔너리로 구현해서 적용해보는 작업입니다.

우리가 잘 아는 가위바위보는 어떻게 승리가 결정될까요? 두 사람이 각각 가위, 바위, 보 중에서 하나를 선택해서 내면, 이 둘을 비교해서 같을 경우에는 무승부, 둘이 서로 다를 경우 둘 사이의 우위를 판단해서 어느 한쪽이 승리가 되고 어느 한쪽이 패배가 되겠죠.

말로 설명하자면 쉬운데 코드로 작성하자면 조금 복잡한 지점이 생깁니다. 컴퓨터는 가위바위보 중 어느 것에 우위가 있는지를 모르거든요. 그래서 두 사람이 선택한 코드를 작성하려면 다음과 같은 코드가 필요하게 됩니다.

var 1= "가위"
var 2= "보"

if 1== 2{
    return "무승부"
}

switch 1{
case "바위":
    return 2== "가위" ? "승리" : "패배"
case "가위":
    return 2== "보" ? "승리" : "패배"
case "보":
    return 2== "바위" ? "승리" : "패배"
}

위 로직으로도 충분히 가위바위보의 승패 여부를 판단할 수 있습니다. 하지만 순환 링크드 리스트와 딕셔너리를 조합해서 응용하는 것으로도 같은 로직을 다르게 표현할 수 있습니다. (당연히 제 오리지널은 아니고, 저도 누군가가 순환 링크드 리스트를 썼다고 해서 나름의 방식으로 응용해본 거예요.)

enum 가위바위보 {
    case 바위, 가위,}

let logic: [ 가위바위보 : 가위바위보 ] = [
    .바위 : .가위,
    .가위 : .,
    .: .바위
]

가위, 바위, 보를 케이스로 갖는 열거형을 생성해주고, 이 열거형 타입을 활용해서 딕셔너리를 생성해 줍시다. 이때 딕셔너리의 key 는 value 에 우위를 갖는 값으로 지정해 주었어요. key 가 가위라면 value 는 보가 되고, key 가 바위라면 value 는 가위가 되는 식이죠. 가위바위보는 서로가 순환하며 우위를 갖는 구조이기 때문에, 이렇게 딕셔너리를 활용하면 딕셔너리의 모든 값들 순환하는 형태가 되도록 만들어줄 수 있습니다. 딕셔너리의 각각의 값을 노드라고 생각한다면, key 를 노드의 값으로, value 는 다음 노드의 링크라고 볼 수 있겠죠.

그러면 우리는 승패 확인을 다음과 같은 방식으로도 구현할 수 있습니다.

var 1= "가위"
var 2= "보"

if 1== 2{
    return "무승부"
}

return logic[1] == 2? "승리" : "패배"

1번이 무엇을 냈는지에 따라서, 바위, 가위, 보 조건마다 각각 구분해서 반복해야 했던 코드가 훨씬 보기에 간편해졌죠. 만약 1번과 2번이 같은 걸 냈다면 무승부를 바로 돌려주고, 아니라면 logic 이라는 딕셔너리에 1번의 핸드를 key 로 입력해서 2번의 핸드와 비교가 가능합니다. 무승부는 위의 if 문에서 걸러주었기 때문에 1번과 2번은 무조건 다른 모양을 냈을 거니까요. 스위치 구문을 활용해 나누는 것 보다는 조금 더 깔끔하게 읽을 수 있는 코드이지 않을까 싶습니다.


outro

글을 작성하다 보니 제가 작성한 방식이 과연 순환 링크드 리스트를 언급할 만한 일인가 싶기는 합니다. 누군가 순환 링크드 리스트를 활용했다고 해서, 이를 조금 더 쉽게 적용해 볼만한 방법이 뭘까 고민해서 이런 방식을 적용해보게 되었어요.

개인적으로는 스위프트의 딕셔너리가 범용성이 꽤 높다는 생각을 하게 됩니다. 서로 다른 타입들을 연결해줄 수 있는 것만으로 훨씬 풍부한 활용이 가능해지는 것 같아요.

엄청나게 배울 내용이 있다기보다는 재미로 보실 수 있는 글이 되었기를 바라면서, 마무리하도록 하겠습니다.

profile
iOS 개발자로 전직하기 위해 공부 중입니다.

0개의 댓글

관련 채용 정보