<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Kelly Dev</title><link>https://kelly-chui.github.io/</link><description>Recent content on Kelly Dev</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Tue, 18 Aug 2026 23:30:00 +0900</lastBuildDate><atom:link href="https://kelly-chui.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>StackDay. 0. Concept</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-concept/</link><pubDate>Sat, 08 Aug 2026 15:36:21 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-concept/</guid><description>&lt;h2 id="시작하기"&gt;시작하기&lt;/h2&gt;
&lt;p&gt;애플 리마인더나 마이크로소프트 To do를 쓰면 매일 해야하는 일들을 관리할 수 있다.&lt;/p&gt;
&lt;p&gt;나도 매일 LeetCode Daily를 풀고, Bing 출석체크를 하고, 매일 TIL 을 적으려고 한다.&lt;/p&gt;
&lt;figure class="media-caption align-center"&gt;&lt;img src="https://kelly-chui.github.io/posts/stackday-dev-log-concept/image-001-optimized-image.webp" alt="" loading="lazy" width="360"&gt;
&lt;/figure&gt;
&lt;p&gt;하지만 기본적으로 Reminder, Todo 앱과 습관 형성 앱은 차이가 있다.&lt;/p&gt;
&lt;p&gt;첫 번째로 기능 요구사항이 다르다. 애플 리마인더는 매일 반복해야 하는 태스크를 하지 않았을 경우에, 날짜가 새로 갱신되지 않고, 그 날짜에 계속 남아있는다. 마이크로소프트 To do는 하루를 빠뜨리면 그 태스크가 사라지지 않고 누적된다.&lt;/p&gt;
&lt;p&gt;내가 원하는 습관 형성 앱은 리마인더의 방식, 마이크로소프트 투 두의 방식 등등을 포괄할 수 있는 앱이었다.&lt;/p&gt;</description></item><item><title>dev-data-server-light. 0. Concept</title><link>https://kelly-chui.github.io/posts/devbox-light-server-00-concept/</link><pubDate>Wed, 24 Jun 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-00-concept/</guid><description>&lt;h2 id="시작하기"&gt;시작하기&lt;/h2&gt;
&lt;p&gt;iOS 프로젝트를 진행하다 보면 생각보다 자주 간단한 API 서버가 필요해진다. 회원가입 화면을 만들거나, 목록 조회 기능을 붙이거나, 이미지 업로드를 테스트할 때도 서버가 필요하다. 물론 실제 백엔드를 구축할 수도 있고, Supabase나 Firebase 같은 BaaS를 사용할 수도 있다. 하지만 작은 개인 프로젝트나 프로토타입 단계에서는 좋은 설계는 아니라고 생각한다.&lt;/p&gt;
&lt;p&gt;특히 처음부터 특정 서비스에 의존하기 시작하면, 정작 내가 만들고 싶은 앱의 기능보다 인프라 설정과 서비스 사용법을 익히는 데 더 많은 시간을 쓰게 된다. 앱 개발을 위한 도구가 필요했는데, 어느 순간 도구를 사용하기 위한 공부를 하고 있는 상황이 되는 것이다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 01. 자바스크립트 기본 환경 설치 및 기본 문법</title><link>https://kelly-chui.github.io/posts/javascript-basics-01-environment-and-syntax/</link><pubDate>Sat, 31 May 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-01-environment-and-syntax/</guid><description>&lt;h1 id="환경-설치"&gt;환경 설치&lt;/h1&gt;
&lt;h2 id="자바스크립트란"&gt;자바스크립트란?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;HTML과 CSS와 함께 클라이언트 측 웹 프로그래밍을 할 수 있도록 돕는 프로그래밍 언어&lt;/li&gt;
&lt;li&gt;C, C++, 자바와 같은 언어에 비해 문법이 쉽고 브라우저에서 바로 실행됨&lt;/li&gt;
&lt;li&gt;조금만 배워도 HTML, CSS와 함께 바로 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="컴파일러-언어와-인터프리터-언어"&gt;컴파일러 언어와 인터프리터 언어&lt;/h3&gt;
&lt;p&gt;자바스크립트는 인터프리터 언어로 작성과 동시에 바로 실행할 수 있는 언어이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;프로그래밍은 일반적으로 컴파일러와 인터프리터라는 과정을 통하여 프로그래밍 진행&lt;/li&gt;
&lt;li&gt;바로 작성한 프로그램을 확인할 수 있는 언어를 인터프리터 언어, 컴파일러 언어는 소스 코드를 기계어로 번역하는 과정이 필요함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="기반-환경-구축하기"&gt;기반 환경 구축하기&lt;/h3&gt;
&lt;p&gt;ES6부터 CLI를 활용해야한다. node.js, npm, react, git등을 활용하려면 터미널을 활용해야 한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Functions (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-01-functions-1/</link><pubDate>Thu, 25 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-01-functions-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="functions"&gt;Functions&lt;/h2&gt;
&lt;p&gt;함수는 특정 작업을 수행하는 독립적인 코드 덩어리이다. 함수에 이름을 지어서 그 함수가 무엇을 하는지를 나타내고, 필요할때 &amp;ldquo;호출(call)&amp;ldquo;할 수 있다.&lt;/p&gt;
&lt;p&gt;스위프트의 함수는 파라미터의 이름이 없는 C-스타일 함수와 파라미터의 이름과 아규먼트 레이블이 모두 있는 Objective-C 스타일 함수를 동시에 표현할 수 있다. 파라미터는 디폴트 값을 가질 수 있고, 파라미터로 받아 값을 변경 시킬 수 있는 in-out 파라미터로도 전달 될 수 있다.&lt;/p&gt;
&lt;p&gt;모든 함수는 파라미터들의 타입과 리턴 타입으로 이루어진 타입을 가지고 있다. 스위프트의 다른 타입들과 마찬가지로 다른 함수에 대한 파라미터로 이 타입을 전달 할 수 있고, 리턴 값으로 사용할 수도 있다. 또한 함수는 중첩할 수 있어 함수 내부에서 함수를 작성 하여 특정 기능에 대한 캡슐화를 할 수 있다.&lt;/p&gt;</description></item><item><title>StackDay. 엔티티와 계산 책임 분리하기</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-derived-value-responsibility/</link><pubDate>Wed, 12 Aug 2026 16:51:04 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-derived-value-responsibility/</guid><description>&lt;p&gt;앞서 도메인, 데이터 모델링한 내용을 실제 코드로 옮기기 시작했다.&lt;/p&gt;
&lt;p&gt;모델 자체의 구조는 이미 정해져 있었지만 코드로 구현하니 &lt;code&gt;Habit Entry&lt;/code&gt;같은 파생 값들은 어디서 생성해야 하는지 책임이 정해지지 않았다.&lt;/p&gt;
&lt;h2 id="completion"&gt;Completion&lt;/h2&gt;
&lt;p&gt;먼저 습관을 수행했다는 사실을 기록하는 &lt;code&gt;Completion&lt;/code&gt;을 구현했다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;habitID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;completedOn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;recordedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Completion&lt;/code&gt;은 저장되는 원본 데이터이므로 완료 사실을 표현하는 데 필요한 값만 가진다.&lt;/p&gt;
&lt;p&gt;미래의 날짜인지, &lt;code&gt;Habit&lt;/code&gt;의 시작일 이전인지, 같은 날짜의 &lt;code&gt;Completion&lt;/code&gt;이 이미 존재하는지와 같은 검증은 &lt;code&gt;Completion&lt;/code&gt; 하나만으로 판단할 수 없기 때문에 넣지 않았다.&lt;/p&gt;</description></item><item><title>StackDay. 데이터 모델링, Entry가 아닌 Completion을 관리해야 하는 이유</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-entry-vs-completion/</link><pubDate>Tue, 11 Aug 2026 16:48:37 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-entry-vs-completion/</guid><description>&lt;p&gt;StackDay의 MVP 범위와 정책을 가지고 앱의 도메인과 데이터를 모델링한다.&lt;/p&gt;
&lt;p&gt;도메인 모델링 -&amp;gt; 데이터 모델링 -&amp;gt; 유즈케이스 검증 순서로 진행하고, 각각의 단계가 이전 단계를 검증하는 방향이다.&lt;/p&gt;
&lt;h2 id="앱의-핵심-동작"&gt;앱의 핵심 동작&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-concept/"&gt;이전 포스트&lt;/a&gt;에서 정한 앱의 컨셉과 정책에서부터, 이 앱이 어떤 동작을 해야 할지 먼저 정리했다.&lt;/p&gt;
&lt;pre class="mermaid" data-mermaid-source="flowchart&amp;#43;LR%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;A%5B%EC%8A%B5%EA%B4%80&amp;#43;%EC%83%9D%EC%84%B1%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;B%5B%EC%8A%B5%EA%B4%80&amp;#43;%EC%B6%94%EC%A0%81%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;C%5B%EB%A7%A4%EC%9D%BC&amp;#43;%EC%88%98%ED%96%89&amp;#43;%EC%97%AC%EB%B6%80&amp;#43;%EA%B8%B0%EB%A1%9D%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;D%5B%EC%8A%A4%ED%8A%B8%EB%A6%AD%EA%B3%BC&amp;#43;%ED%86%B5%EA%B3%84&amp;#43;%EA%B3%84%EC%82%B0%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;E%5B%EC%8A%B5%EA%B4%80&amp;#43;%EC%A2%85%EB%A3%8C%5D%0A%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;A&amp;#43;--%3E&amp;#43;B&amp;#43;--%3E&amp;#43;C&amp;#43;--%3E&amp;#43;D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;B&amp;#43;--%3E&amp;#43;E"&gt;&lt;/pre&gt;&lt;p&gt;사용자가 습관을 만들면 그날부터 습관의 추적이 시작된다. 사용자는 매일 습관을 수행했는지 기록하고, 앱은 누적된 기록을 바탕으로 현재 스트릭과 통계를 보여준다. 더 이상 이어가지 않을 습관은 추적을 종료할 수 있다.&lt;/p&gt;</description></item><item><title>dev-data-server-light. 1. System</title><link>https://kelly-chui.github.io/posts/devbox-light-server-01-system-module/</link><pubDate>Thu, 25 Jun 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-01-system-module/</guid><description>&lt;p&gt;프로젝트에서 제일 간단한 기능과 구조를 가지기 때문에 가장 먼저 System 모듈을 만들었다.&lt;/p&gt;
&lt;h2 id="system-모듈의-기능"&gt;System 모듈의 기능&lt;/h2&gt;
&lt;p&gt;System 모듈이 제공하는 기능은 단 두 가지뿐이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GET /system/status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GET /system/uptime&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;status&lt;/code&gt;는 서버가 정상적으로 동작하는지 알려주고, &lt;code&gt;uptime&lt;/code&gt;은 서버가 실행된 이후 얼마나 시간이 지났는지를 반환한다.&lt;/p&gt;
&lt;p&gt;비즈니스 로직도 없고, 데이터베이스도 필요하지 않으며, 파일 시스템도 다루지 않기 때문에 구조를 검증하는데 가장 좋다고 판단했다.&lt;/p&gt;
&lt;h2 id="구조-검증"&gt;구조 검증&lt;/h2&gt;
&lt;p&gt;System 모듈을 만들면서 확인하고 싶었던 것은 기능이 아니라 구조였다. 당시에 생각했던 구조는 다음과 같았다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 02. 연산자와 명령문</title><link>https://kelly-chui.github.io/posts/javascript-basics-02-operators-and-statements/</link><pubDate>Sun, 01 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-02-operators-and-statements/</guid><description>&lt;h1 id="기본-명령어"&gt;기본 명령어&lt;/h1&gt;
&lt;h3 id="표현식"&gt;표현식&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;문장 표현식이 하나 이상 모일 경우, 마지막에 &lt;strong&gt;종결 의미로 세미콜론(;)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="프로그램"&gt;프로그램&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;문장이 모이면 프로그램이 됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;문장을 작성하고, 다음 줄에 문장을 작성하면 앞 문장 끝에 세미콜론이 없어도 자바스크립트 &lt;strong&gt;엔진이 자동으로 세미콜론 추가&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;자바스크립트 엔진이 세미콜론을 생략한 줄이 다음 줄과 이어지고 있다고 판단하면?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 세미콜론을 안붙이면
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 이렇게 해석될 수 있다
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="예악어"&gt;예악어&lt;/h3&gt;
&lt;p&gt;자바스크립트 문법을 규정짓기 위해 자바스크립트 언어 사양에서 사용하는 특수한 키워드는 식별자로 사용하지 않는 편이 좋다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Functions (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-02-functions-2/</link><pubDate>Fri, 26 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-02-functions-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="function-argument-labels-and-parameter-names"&gt;Function Argument Labels and Parameter Names&lt;/h3&gt;
&lt;p&gt;함수의 파라미터들은 각각 아규먼트 레이블(Argument Labels)과 파라미터 이름(Parameter Names)을 가지고 있다. 아규먼트 레이블은 함수를 호출할 때 인자와 함께 사용되며, 파라미터 이름은 함수를 구현할 때 사용한다. 기본적으로, 파라미터 이름이 인자 레이블이 된다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstParameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secondParameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// In the function body, firstParameterName and secondParameterName&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// refer to the argument values for the first and second parameters.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;someFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;firstParameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secondParameterName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;모든 파라미터들은 고유한 이름을 가져야 한다. 여러 개의 파라미터들이 같은 아규먼트 레이블을 가질 수도 있지만, 고유한 아규먼트 레이블을 사용하면 코드의 가독성이 증가한다.&lt;/p&gt;</description></item><item><title>dev-data-server-light. 2. Database CRUD</title><link>https://kelly-chui.github.io/posts/devbox-light-server-02-db-crud/</link><pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-02-db-crud/</guid><description>&lt;p&gt;시스템 모듈을 만든 이후에, 아마도 가장 많이 쓰게 될 DB 모듈을 만들었다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/devbox-light-server-02-db-crud/image-001-optimized-image.webp"&gt;&lt;p&gt;당시에는 구조도 시스템 모듈과 동일하다고 생각했다. Router가 DB 인터페이스에 의존하고, 이를 구현한 구현체를 주입받는 방식으로 DIP와 DI를 동시에 적용했다.&lt;/p&gt;
&lt;p&gt;이 과정 중에서&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;naming bias 해결하기&lt;/li&gt;
&lt;li&gt;id 생성 책임 위치&lt;/li&gt;
&lt;li&gt;기존 아키텍처의 문제점 -&amp;gt; 서비스 레이어 도입해서 해결하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;에 대한 고민을 했다. 아래는 고민과 해결 과정이다.&lt;/p&gt;
&lt;h2 id="crud부터-만들기"&gt;CRUD부터 만들기&lt;/h2&gt;
&lt;p&gt;Mock Server라도 최소한 CRUD는 제공해야 한다. 처음부터 구현체를 만들 필요는 없으므로, 라우터와 인터페이스까지만 만들도록 프롬프트를 작성했다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 03. 자바스크립트 사용자 정의 자료형 활용</title><link>https://kelly-chui.github.io/posts/javascript-basics-03-custom-types/</link><pubDate>Sun, 01 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-03-custom-types/</guid><description>&lt;h2 id="조건문"&gt;조건문&lt;/h2&gt;
&lt;h3 id="if-조건문"&gt;if 조건문&lt;/h3&gt;
&lt;p&gt;bool 표현식이 &lt;code&gt;true&lt;/code&gt;이면 문장을 실행, &lt;code&gt;false&lt;/code&gt;이면 문장을 무시&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;짝수입니다!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;홀수입니다!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;오전입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;오후입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="if-else-조건문"&gt;if else 조건문&lt;/h3&gt;
&lt;p&gt;조건이 합당하지 않은 경우의 표현식도 포함하는 조건문&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;짝수입니다!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;홀수입니다!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;오전입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;오후입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="중첩-조건문"&gt;중첩 조건문&lt;/h3&gt;
&lt;p&gt;조건문이 중첩된 형태&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getHours&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;아침 먹을 시간입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;점심 먹을 시간입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;저녁 먹을 시간입니다.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="if-else-if-조건문"&gt;if else if 조건문&lt;/h3&gt;
&lt;p&gt;중복되지 않는 세 가지 이상의 조건을 구분할 때 사용&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Functions (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-03-functions-3/</link><pubDate>Sat, 27 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-03-functions-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="function-types"&gt;Function Types&lt;/h3&gt;
&lt;p&gt;모든 함수는 파라미터들의 타입들과 리턴 값의 타입으로 이루어진 특정한 &lt;em&gt;함수 타입&lt;/em&gt; 을 가지고 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addTwoInts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;multiplyTwoInts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위의 예시에서 두 함수는 두 개의 정수 값을 받아 정수 값을 리턴한다. 두 함수 모두 (Int, Int) -&amp;gt; Int 타입이며, 이는 &amp;ldquo;두 개의 Int 타입 파라미터를 받아 Int 타입을 리턴하는 함수&amp;rdquo; 라는 의미이다.&lt;/p&gt;
&lt;p&gt;파라미터와 리턴 값이 없는 함수의 예시이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;printHelloWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello, world&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 함수의 타입은 () -&amp;gt; Void 이고 &amp;ldquo;파라미터가 없고 리턴값이 Void인 함수&amp;rdquo; 라는 의미를 가진다.&lt;/p&gt;</description></item><item><title>dev-data-server-light. 3. Database Implementation</title><link>https://kelly-chui.github.io/posts/devbox-light-server-03-db-implementation/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-03-db-implementation/</guid><description>&lt;p&gt;DB 모듈의 인터페이스와 서비스 레이어를 만들었으므로, 실제 구현체를 만들어야 한다. 우선 인 메모리(In-Memory)로 가볍게 구현체를 만들었다.&lt;/p&gt;
&lt;h2 id="인-메모리-데이터-저장소"&gt;인 메모리 데이터 저장소&lt;/h2&gt;
&lt;p&gt;인 메모리 방식을 선택한 이유는 첫째로 처음부터 SQL이나 JSON 파일 기반 저장소를 이용해서 구현체를 만드는 것 보다는, 가장 단순한 구현체를 만들어서 DB 기능을 검증하고 빠르게 다음 기능을 만들기 위해서이다. 외부 의존성도 없고, 설정도 필요 없고, 테스트도 쉽다.&lt;/p&gt;
&lt;h2 id="구현하기"&gt;구현하기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;RecordStore&lt;/code&gt; 인터페이스를 다시 보면 다음과 같다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ts" data-lang="ts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;RecordStore&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;StoredRecord&lt;/span&gt;&lt;span class="err"&gt;[]&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;StoredRecord&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="na"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;: &lt;span class="kt"&gt;RecordData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;StoredRecord&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;: &lt;span class="kt"&gt;RecordData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;collection&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;구현체는 이 계약을 그대로 만족하면 된다. 중요한 것은 구현체는 Express를 몰라야하고 순수하게 TypeScript 코드로 짜여야 한다. HTTP 요청이나 라우팅 같은 것은 Router가 책임져야 한다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 04. 자바스크립트 함수</title><link>https://kelly-chui.github.io/posts/javascript-basics-04-functions/</link><pubDate>Mon, 02 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-04-functions/</guid><description>&lt;h2 id="함수-생성-방법"&gt;함수 생성 방법&lt;/h2&gt;
&lt;h3 id="익명-함수"&gt;익명 함수&lt;/h3&gt;
&lt;p&gt;이름을 붙이지 않고 함수 생성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;함수를 호출하면 함수 내부의 코드 덩어리가 모두 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;helloWorld&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 함수 호출
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 함수 자체를 호출
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Hello, World!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// f () {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// console.log(&amp;#34;Hello, World!&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;// }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="선언적-함수"&gt;선언적 함수&lt;/h3&gt;
&lt;p&gt;이름을 붙여 함수를 생성&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 함수 호출
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 함수 자체를 호출
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Hello, World!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// f () {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// console.log(&amp;#34;Hello, World!&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;// }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="화살표-함수"&gt;화살표 함수&lt;/h3&gt;
&lt;p&gt;하나의 표현식을 리턴하는 함수를 만들 때는 중괄호 생략 가능&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Closures (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-04-closures-1/</link><pubDate>Sun, 28 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-04-closures-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="closures"&gt;Closures&lt;/h2&gt;
&lt;p&gt;클로저는 코드 내부에서 전달되고 사용할 수 있는 독립적인 코드 블록이다. 클로저는 C, Objective-C의 블록이나 다른 언어들의 lambda와 유사하다.&lt;/p&gt;
&lt;p&gt;클로저는 자신이 정의된 컨텍스트에 있는 상수나 변수의 참조를 캡처하고 저장할 수 있다. 이를 캡쳐한 상수나 변수에 대한 클로징 오버(closing over)라고 한다. 이 경우에 스위프트가 모든 메모리 관리를 해준다.&lt;/p&gt;
&lt;p&gt;함수(Function)는 클로저의 특수한 케이스이며, 클로저는 다음과 같은 세가지 형태가 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어떠한 값도 캡처하지 않고, 이름이 있는 전역 함수&lt;/li&gt;
&lt;li&gt;자신을 둘러 싼 함수 내부의 값을 캡처하고, 이름이 있는 중첩 함수&lt;/li&gt;
&lt;li&gt;자신을 둘러싼 컨텍스트의 값을 캡처하고, 이름이 없는 클로저 표현식&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;일반적인 상황에서 다음과 같은 최적화를 통해서 클로저를 짧고 난잡하지 않게 만들 수 있다.&lt;/p&gt;</description></item><item><title>dev-data-server-light. 4. File Storage</title><link>https://kelly-chui.github.io/posts/devbox-light-server-04-file-storage/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-04-file-storage/</guid><description>&lt;p&gt;DB 모듈을 마무리하고, 다음으로 구현한 것은 File Storage 모듈이다. DB 모듈과 크게 다르지 않을 것이라고 생각했다. 우선 CRUD 비슷한 메소드를 처리하고, 구조는 DB 모듈에서 충분히 다듬었기 때문이다. 하지만 실제로는 DB보다 인터페이스를 어떻게 정의할 것인지에 대한 고민이 더 많았다.&lt;/p&gt;
&lt;h2 id="인터페이스-만들기"&gt;인터페이스 만들기&lt;/h2&gt;
&lt;p&gt;처음 작성한 프롬프트는 다음과 같다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Create the initial FileStorage contract in src/storage.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Requirements:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Define a FileStorage interface.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- The interface is responsible only for storing and retrieving binary file contents.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- It should not manage file metadata, ids, ownership, permissions, or database records.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Use Buffer for file contents.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Include only the minimal operations required for file storage:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - save(path: string, content: Buffer): Promise&amp;lt;void&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - read(path: string): Promise&amp;lt;Buffer&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - delete(path: string): Promise&amp;lt;void&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - exists(path: string): Promise&amp;lt;boolean&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Add minimal domain errors if necessary.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;For this step, create only the contract and related types.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Do not implement any storage implementation yet.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;로컬 파일 시스템을 의식하고 있어서 의심 없이 &lt;code&gt;path&lt;/code&gt;라는 이름을 사용했는데, 이 때문에 인터페이스가 구현체를 닮아버리게 되었다. &lt;code&gt;path&lt;/code&gt;는 과연 인터페이스를 대표할 수 있는 네이밍인가?&lt;/p&gt;</description></item><item><title>JavaScript Basics. 05. 자바스크립트 내장 객체</title><link>https://kelly-chui.github.io/posts/javascript-basics-05-built-in-objects/</link><pubDate>Tue, 03 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-05-built-in-objects/</guid><description>&lt;h2 id="객체"&gt;객체&lt;/h2&gt;
&lt;h3 id="배열"&gt;배열&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;기본 형태&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;사과&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;바나나&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;망고&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;딸기&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// &amp;#39;사과&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;/ &amp;#39;바나나&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;배열은 요소에 접근할 때 인덱스를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="객체-기본"&gt;객체 기본&lt;/h3&gt;
&lt;p&gt;배열과 다르게 키를 통해서 접근하게 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;객체 선언&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;제품명&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;7D 건조 망고&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;유형&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;당절임&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;원산지&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;필리핀&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="err"&gt;// {제품명: &amp;#39;7D 건조 망고&amp;#39;, 유형: &amp;#39;당절임&amp;#39;, 원산지: &amp;#39;필리핀&amp;#39;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;객체 접근&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;제품명&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// &amp;#39;7D 건조 망고&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;유형&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// 당절임
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;원산지&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// 필리핀
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;제품명&lt;/span&gt; &lt;span class="c1"&gt;// &amp;#39;7D 건조 망고&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;유형&lt;/span&gt; &lt;span class="c1"&gt;// &amp;#39;당절임&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;원산지&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;/ &amp;#39;필리핀&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="객체와-반복문"&gt;객체와 반복문&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;for in&lt;/code&gt; 반복문을 사용해 객체에 반복문을 적용&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;바나나&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="메소드"&gt;메소드&lt;/h3&gt;
&lt;p&gt;객체의 속성 중 자료형이 함수인 속성&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Closures (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-05-closures-2/</link><pubDate>Mon, 29 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-05-closures-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="capturing-values"&gt;Capturing Values&lt;/h3&gt;
&lt;p&gt;클로저는 자신이 정의된 컨텍스트에서 상수나 변수를 캡처할 수 있다. 캡처한 상수나 변수가 정의되어있는 범위가 더 이상 존재하지 않아도 클로저의 본문에서 그 변수나 상수를 참조하고 수정할 수 있다.&lt;/p&gt;
&lt;p&gt;스위프트에서 값을 캡쳐하는 가장 간단한 형태의 클로저는 중첩 함수이다. 중첩 함수는 외부 함수(둘러싸고 있는 함수)내부에 선언된 변수나 상수, 그리고 아규먼트를 캡처할 수 있다.&lt;/p&gt;
&lt;p&gt;다음 예시는 incrementer라는 중첩 함수를 가지고 있는 makeIncrementer 함수의 예시이다. incrementer() 함수는 runningTotal과 amount 두개의 변수를 캡처한다. 이 값을 캡처한 다음에 incrementer는 호출될 때마다 amount만큼 runningTotal을 증가시키는 클로저가 되고, makeIncrementer에 의해 리턴 된다.&lt;/p&gt;</description></item><item><title>devbox-light-server (5). Auth</title><link>https://kelly-chui.github.io/posts/devbox-light-server-05-auth/</link><pubDate>Sat, 08 Aug 2026 16:27:42 +0900</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-05-auth/</guid><description>&lt;h2 id="auth-설계하기"&gt;Auth 설계하기&lt;/h2&gt;
&lt;p&gt;개발용 목서버에서 실제 서비스 수준의 인증 시스템을 구현하지 않고도, 클라이언트에서 사용하는 로그인과 인증 흐름을 테스트할 수 있도록 Auth 기능을 추가했다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;로그인 요청을 보낸다.&lt;/li&gt;
&lt;li&gt;access token을 발급받는다.&lt;/li&gt;
&lt;li&gt;Authorization 헤더에 token을 실어 요청한다.&lt;/li&gt;
&lt;li&gt;현재 로그인된 유저를 확인한다.&lt;/li&gt;
&lt;li&gt;로그아웃으로 token을 무효화한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;JWT, 비밀번호, OAuth, Refresh Token, 보안 같은 기능은 의도적으로 제외했다. 프로덕션 인증 로직을 구현하려는 글이 아니라, 개발용 Mock 서버에서 클라이언트의 로그인, 인증, 로그아웃 흐름을 확인하는 것이 목적이기 때문이다.&lt;/p&gt;
&lt;h3 id="최소한의-auth-구조"&gt;최소한의 Auth 구조&lt;/h3&gt;
&lt;p&gt;첫 단계에서는 &lt;code&gt;DatabaseService&lt;/code&gt;를 그대로 사용했다. &lt;code&gt;users&lt;/code&gt; 컬렉션을 만들어서 그 레코드 ID를 유저 ID로 사용해 로그인할 수 있도록 했다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 06. 브라우저 및 문서 객체</title><link>https://kelly-chui.github.io/posts/javascript-basics-06-browser-and-document-object/</link><pubDate>Fri, 06 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-06-browser-and-document-object/</guid><description>&lt;h2 id="브라우저-객체-모델"&gt;브라우저 객체 모델&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;웹 브라우저와 관련된 객체의 집합&lt;/li&gt;
&lt;li&gt;대표적인 브라우저 객체 모델
&lt;ul&gt;
&lt;li&gt;window, location, navigator, history, screen, document…&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt="Screenshot 2025-06-06 at 12.30.02\u202fPM.png" loading="lazy" src="https://kelly-chui.github.io/posts/javascript-basics-06-browser-and-document-object/image-001-optimized-image.webp"&gt;&lt;h3 id="window-객체"&gt;&lt;code&gt;window&lt;/code&gt; 객체&lt;/h3&gt;
&lt;p&gt;브라우저 기반 자바스크립트의 최상위 객체&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alert()&lt;/code&gt;, &lt;code&gt;prompt()&lt;/code&gt;함수 모두 window 객체의 메소드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;open(URL, name, features, replace)&lt;/code&gt;메소드를 통해서 window 객체 생성 가능
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;URL&lt;/code&gt;: 열고자 하는 HTML 페이지의 URL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;: 윈도우 간 통신하는 데 사용하는 윈도우 이름&lt;/li&gt;
&lt;li&gt;&lt;code&gt;features&lt;/code&gt;: 윈도우 출력 모양을 지정하는 옵션
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;height&lt;/code&gt;: 새 윈도우의 높이&lt;/li&gt;
&lt;li&gt;&lt;code&gt;width&lt;/code&gt;: 새 윈도우의 너비&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;replace&lt;/code&gt;: URL이 새로운 것인가, 기존의 문서를 대체할 것인가를 나타내는 부울리언 값&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;window 객체는 자신의 형태와 위치를 변경할 수 있도록 메소드 제공
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;moveBy(x, y)&lt;/code&gt;: 윈도우의 위치를 상대적으로 이동합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;moveTo(x, y)&lt;/code&gt;: 윈도우의 위치를 절대적으로 이동합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resizeBy(x, y)&lt;/code&gt;: 윈도우의 크기를 상대적으로 지정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;resizeTo(x, y)&lt;/code&gt;: 윈도우의 크기를 절대적으로 지정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;close()&lt;/code&gt;: 윈도우를 닫습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="screen-객체"&gt;&lt;code&gt;screen&lt;/code&gt; 객체&lt;/h3&gt;
&lt;p&gt;웹 브라우저의 화면이 아닌 운영체제 화면의 속성을 가치는 객체&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Closures (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-06-closures-3/</link><pubDate>Mon, 29 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-06-closures-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="escaping-closures"&gt;Escaping Closures&lt;/h3&gt;
&lt;p&gt;클로저가 함수의 아규먼트로 전달이 됐는데, 함수가 리턴된 이후에 클로저가 호출되면 이를 함수를 탈출(escape)했다고 한다. 클로저를 파라미터로 받는 함수를 작성할 때, 파라미터의 타입 뒤에 @escaping을 작성해서 그 클로저가 탈출 가능하다는 것을 나타낼 수 있다.&lt;/p&gt;
&lt;p&gt;클로저가 함수를 탈출하는 한가지 방법은 외부 변수에 저장되는 것이다. 예를 들어 많은 비동기 작업을 시작 하는 함수들은 클로저 아규먼트를 컴플리션 핸들러(completion handler)로 사용한다. 함수는 비동기 작업을 시작하고 리턴되지만, 클로저는 비동기 작업이 끝날때까지 호출되지 않는다. 따라서 나중에 호출되기 위해 탈출이 필요하다. 예를 들면:&lt;/p&gt;</description></item><item><title>devbox-light-server (6). Json 영속성</title><link>https://kelly-chui.github.io/posts/devbox-light-server-06-persistence/</link><pubDate>Mon, 10 Aug 2026 14:14:08 +0900</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-06-persistence/</guid><description>&lt;p&gt;MVP의 마지막 기능으로 서버를 재시작해도 데이터가 사라지지 않도록 영속성을 추가했다.&lt;/p&gt;
&lt;p&gt;이번 포스트에서는 devbox-light-server에 DB, Storage, Token Storage에서 영속성을 가진 저장 방식을 구현해서 in-memory 대신 사용할 수 있도록 만든다.&lt;/p&gt;
&lt;p&gt;프로토타입이었던 dev-data-server에서는 시작부터 SQL 의존성을 가지고 시작했지만, devbox-light-server는 아주 얇은 in-memory 구현만 가지고 있다.&lt;/p&gt;
&lt;p&gt;MVP 마지막에 영속성을 넣는 이유는 서버를 구현할 때, 특정 구현에 휘둘리지 않기 위해서다. dev-data-server에서 SQL을 빠르게 들여와서, 결국 프로젝트가 SQL 래퍼가 된 느낌이 있다.&lt;/p&gt;
&lt;p&gt;당연히 Service 레이어는 Repository의 인터페이스에만 의존하므로 어떤 방법을 쓰든 단순히 구현체만 갈아 끼우고, 의존성 생성, 연결 부분을 제외하고는 어떠한 코드에도 변화가 없어야 한다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 07. 자바스크립트 예외처리 및 이벤트 처리</title><link>https://kelly-chui.github.io/posts/javascript-basics-07-errors-and-events/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-07-errors-and-events/</guid><description>&lt;h2 id="예외-처리"&gt;예외 처리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;예외 → 실행에 문제가 발생하면 자동 중단됨&lt;/li&gt;
&lt;li&gt;예외 처리 → 오류에 대처할 수 있게 하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="예외와-기본-예외-처리"&gt;예외와 기본 예외 처리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;TypeError 기본 예외 처리
&lt;ul&gt;
&lt;li&gt;사전에 해당 데이터가 &lt;code&gt;undefined&lt;/code&gt;인지 조건문으로 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="고급-예외-처리"&gt;고급 예외 처리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;try&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;, &lt;code&gt;finally&lt;/code&gt; 구문&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 예외 발생
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 예외 처리
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 무조건 실행
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;catch&lt;/code&gt;구문, &lt;code&gt;finally&lt;/code&gt;구문 생략 가능&lt;/p&gt;
&lt;h3 id="예외-객체"&gt;예외 객체&lt;/h3&gt;
&lt;p&gt;예외가 발생하면 어떤 예외가 발생했는지 정보를 전달함, &lt;code&gt;catch&lt;/code&gt; 구문의 괄호 안의 변수&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Enumerations (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-07-enumerations-1/</link><pubDate>Tue, 30 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-07-enumerations-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="enumerations"&gt;Enumerations&lt;/h2&gt;
&lt;p&gt;열거형은 연관된 값들을 공통된 타입으로 묶은 그룹이며, 타입 안전(type-safe)하게 사용하게 해준다.&lt;/p&gt;
&lt;p&gt;스위프트의 열거형은 유연하다. 각 케이스에 값을 할당하지 않아도 되며, 스트링, 캐릭터, 정수, 실수등을 각 열거형 케이스에 제공할 수 있다.&lt;/p&gt;
&lt;p&gt;스위프트에서 열거형은 그 자체로 일급 객체다. 컴퓨티드 프로퍼티(computed properties)나 인스턴스 메소드(instance method)와 같은, 기존에는 클래스에서만 사용할 수 있었던 많은 기능들을 가져왔고, 초기 케이스 값을 설정하는 이니셜라이저도 정의할 수 있으며, 프로토콜을 상속 받을 수도 있다.&lt;/p&gt;
&lt;h3 id="enumeration-syntax"&gt;Enumeration Syntax&lt;/h3&gt;
&lt;p&gt;열거형을 작성할 때는 enum 키워드를 사용하여 한 쌍의 중괄호 안에 작성한다.&lt;/p&gt;</description></item><item><title>devbox-light-server (7). Dockerizing, MVP 마무리</title><link>https://kelly-chui.github.io/posts/devbox-light-server-07-dockerizing/</link><pubDate>Mon, 10 Aug 2026 17:42:56 +0900</pubDate><guid>https://kelly-chui.github.io/posts/devbox-light-server-07-dockerizing/</guid><description>&lt;h2 id="도커라이징"&gt;도커라이징&lt;/h2&gt;
&lt;p&gt;영속성까지 추가했으므로 이제 서버를 하나의 실행 단위로 묶을 차례다.&lt;/p&gt;
&lt;p&gt;지금까지는 로컬에서 Node.js를 설치하고, 의존성을 설치하고, TypeScript를 빌드한 다음 서버를 실행했다. 혼자 개발할 때는 큰 문제가 없지만, 이 서버를 다른 환경에서 실행하려면 매번 같은 준비 과정을 반복해야 한다.&lt;/p&gt;
&lt;p&gt;도커라이징은 이 과정을 이미지 안에 고정하는 작업이다. 이 프로젝트에서는 Express 서버를 빌드하고, 실행에 필요한 파일만 담은 뒤, &lt;code&gt;.data&lt;/code&gt; 디렉터리를 기준으로 데이터를 유지할 수 있도록 구성했다.&lt;/p&gt;
&lt;h3 id="dockerfile-작성하기"&gt;Dockerfile 작성하기&lt;/h3&gt;
&lt;p&gt;Dockerfile은 두 단계로 나눴다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dockerfile" data-lang="dockerfile"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:24-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/app&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; package.json package-lock.json ./&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; npm ci&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; tsconfig.json tsconfig.build.json ./&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; src ./src&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; npm run build&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;첫 번째 &lt;code&gt;build&lt;/code&gt; 단계에서는 개발 의존성을 포함해서 설치하고 TypeScript를 빌드한다. &lt;code&gt;npm run build&lt;/code&gt;를 실행하면 &lt;code&gt;dist&lt;/code&gt; 디렉터리가 만들어진다.&lt;/p&gt;</description></item><item><title>JavaScript Basics. 08. 자바스크립트 API 활용 및 그림판 프로그램 만들기</title><link>https://kelly-chui.github.io/posts/javascript-basics-08-api-and-paint-app/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-basics-08-api-and-paint-app/</guid><description>&lt;h2 id="api-활용"&gt;API 활용&lt;/h2&gt;
&lt;h3 id="클라이언트-측-고유-기술-요소"&gt;클라이언트 측 고유 기술 요소&lt;/h3&gt;
&lt;p&gt;웹브라우저에서 동작하는 자바스크립트를 클라이언트 측 자바스크립트라 함&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클라이언트 측 자바스크립트 구성
&lt;ul&gt;
&lt;li&gt;ECMAScript가 규정한 코어 언어와 웹 브라우저의 API(Application Program Interface)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;웹 브라우저의 주요 API
&lt;ul&gt;
&lt;li&gt;window 인터페이스
&lt;ul&gt;
&lt;li&gt;자바스크립트로 브라우저 및 창을 제어하는 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DOM
&lt;ul&gt;
&lt;li&gt;자바스크립트 HTML 문서의 요소를 제어하는 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;XMLHttpRequest
&lt;ul&gt;
&lt;li&gt;서버와 비동기로 통신하는 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="서버-측-자바스크립트의-고유-기술-요소"&gt;서버 측 자바스크립트의 고유 기술 요소&lt;/h3&gt;
&lt;p&gt;웹 서버에서 동작하는 자바스크립트&lt;/p&gt;
&lt;p&gt;웹 서버를 구현하는데 Perl, PHP, Python, Ruby 등의 프로그래밍 언어를 이용&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Enumerations (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-08-enumerations-2/</link><pubDate>Wed, 31 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-08-enumerations-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="raw-values"&gt;Raw Values&lt;/h3&gt;
&lt;p&gt;Associated Values 섹션에서는 열거형의 케이스가 다른 타입의 연관값을 저장하는 방법을 보여줬다. 연관 값 대신, 열거형 케이스들은 같은 타입의 디폴트 값-원시 값(raw values)-을 미리 가지고 있을 수도 있다.&lt;/p&gt;
&lt;p&gt;다음은 ASCII값을 원시값으로 사용하는 예시이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;ASCIIControlCharacter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Character&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;tab&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;lineFeed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;carriageReturn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;열거형 ASCIIControlCharacter의 원시 값은 Character 타입으로 정의되어 있고, ASCII 제어 문자로 설정되어 있다.&lt;/p&gt;
&lt;p&gt;원시 값은 어떠한 자료형이든 될 수 있으며, 각 원시 값은 열거형을 선언할 때 고유해야 한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Structures And Classes (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-09-structures-and-classes-1/</link><pubDate>Thu, 01 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-09-structures-and-classes-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="structures-and-classes"&gt;Structures and Classes&lt;/h2&gt;
&lt;p&gt;스트럭처와 클래스는 범용성 있는 유연한 구조이다. 상수, 변수, 함수를 작성하는 것 처럼 프로퍼티와 메소드를 작성하여 스트럭처와 클래스에 기능을 부여할 수 있다.&lt;/p&gt;
&lt;h3 id="comparing-structures-and-classes"&gt;Comparing Structures and Classes&lt;/h3&gt;
&lt;p&gt;스트럭처와 클래스는 많은 공통점을 가지고 있다. 둘 다 다음과 행동을 할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;값을 저장하기 위한 프로퍼티 정의&lt;/li&gt;
&lt;li&gt;기능(functionality)을 위한 메소드 정의&lt;/li&gt;
&lt;li&gt;서브스크립트 구문을 통하여 값에 접근할 수 있게 하는 서브스크립트 정의&lt;/li&gt;
&lt;li&gt;초기 값을 설정하기 위한 이니셜라이저 정의&lt;/li&gt;
&lt;li&gt;기본 구현보다 확장된 기능을 위한 확장성&lt;/li&gt;
&lt;li&gt;특정 종류에 대한 표준 기능을 제공하는 프로토콜 준수&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;클래스는 스트럭처가 없는 추가 기능들이 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Structures And Classes (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-10-structures-and-classes-2/</link><pubDate>Thu, 01 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-10-structures-and-classes-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="structures-and-enumerations-are-value-types"&gt;Structures and Enumerations Are Value Types&lt;/h3&gt;
&lt;p&gt;값 타입은 변수나 상수에 할당되거나 함수에 전달될 때, 값이 복사되는 타입이다. 스위프트의 정수, 실수, 부울, 문자열, 배열, 딕셔너리와 같은 기본 타입들은 모두 값 타입이고 실제로 스트럭처로 구현되어있다.&lt;/p&gt;
&lt;p&gt;스위프트에서 모든 스트럭처와 열거형과 그 값 타입 프로퍼티들은 코드 안에서 복사되어 전달된다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
배열, 딕셔너리, 문자열과 같은 콜렉션은 전달(혹은 할당)될 때, 즉시 복사되지 않고 수정 작업이 이루어졌을때 복사를 하는 최적화가 되어있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;hd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Resolution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cinema&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hd&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 예시는 &lt;a href="https://junmusu.tistory.com/79" title="앞선 예시"&gt;앞선 예시&lt;/a&gt;에 나온 스트럭처 Resolution의 상수 인스턴스 hd를 선언하고 프로퍼티를 초기화한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Properties (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-11-properties-1/</link><pubDate>Fri, 02 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-11-properties-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="properties"&gt;Properties&lt;/h2&gt;
&lt;p&gt;프로퍼티는 특정 클래스, 스트럭처, 열거형에 값을 연관시킨다. 저장 프로퍼티는 변수나 상수의 값을 인스턴스의 일부로 저장하고, 컴퓨티드 프로퍼티는 값을 저장하기보다는 계산한다. 컴퓨티드 프로퍼티와 다르게, 저장 프로퍼티는 열거형에서 쓸 수 없다.&lt;/p&gt;
&lt;p&gt;저장 프로퍼티와 컴퓨티드 프로퍼티는 인스턴스와 연결되는 반면, 다르게 타입 프로퍼티는 타입 그 자체에 연결된다.&lt;/p&gt;
&lt;p&gt;추가로 프로퍼티 값의 변화를 모니터링 하고, 커스텀 액션으로 반응할 수 있는 프로퍼티 옵저버를 사용할 수도 있다. 프로퍼티 옵저버는 저장 프로퍼티에서 직접 정의하여 추가할 수 있으며, 서브클래스한태 상속된다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Properties (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-12-properties-2/</link><pubDate>Fri, 02 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-12-properties-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="property-observers"&gt;Property Observers&lt;/h3&gt;
&lt;p&gt;프로퍼티 옵저버(Property Observer)는 프로퍼티 값의 변화를 관측하고 반응한다. 프로퍼티 옵저버는 새로 설정된 값이 이전의 값과 같더라도, 프로퍼티의 값이 설정 될 때 마다 반응한다.&lt;/p&gt;
&lt;p&gt;프로퍼티 옵저버는 다음의 위치들에 추가할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;직접 정의한 저장 프로퍼티&lt;/li&gt;
&lt;li&gt;상속받은 저장 프로퍼티&lt;/li&gt;
&lt;li&gt;상속받은 컴퓨티드 프로퍼티&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;서브클래스에서 상속받은 프로퍼티를 오버라이드 하여 프로퍼티 옵저버를 추가할 수 있다. 직접 정의한 컴퓨티드 프로퍼티의 경우에는 setter를 사용하면 프로퍼티 옵저버를 사용하지 않고도 값의 변화를 관측하고 응답할 수 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Properties (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-13-properties-3/</link><pubDate>Mon, 05 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-13-properties-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="type-properties"&gt;Type Properties&lt;/h3&gt;
&lt;p&gt;인스턴스 프로퍼티는 특정 타입의 인스턴스에 속하는 프로퍼티이다. 새로운 인스턴스를 만들때 마다, 인스턴스는 다른 인스턴스와 구분되는 프로퍼티 집합이 생긴다.&lt;/p&gt;
&lt;p&gt;인스턴스가 아닌 타입 자체에 속하는 프로퍼티도 있다. 이러한 프로퍼티를 타입 프로퍼티라고 하며, 얼마나 많은 그 타입의 인스턴스를 생성했느냐에 관련없이 단 하나만 존재한다.&lt;/p&gt;
&lt;p&gt;타입 프로퍼티는 특정 타입의 모든 인스턴스들이 보편적으로 사용할 값을 정의할 때 유용하다. (C의 static이랑 유사하다)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
타입 그 자체는 이니셜라이저가 없기 때문에, 인스턴스 프로퍼티와 다르게 타입 프로퍼티는 저장 프로퍼티일 때 반드시 디폴트 값을 줘야한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Methods (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-14-methods-1/</link><pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-14-methods-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="methods"&gt;Methods&lt;/h2&gt;
&lt;p&gt;메소드는 특정 타입에 연관된 함수이다. 클래스, 스트럭처, 열거형은 인스턴스로 작업하기 위한 기능이나 작업은 캡슐화 하기 위해 인스턴스 메소드를 선언할 수 있고, 타입 그 자체에 연관된 타입 메소드도 선언할 수 있다.&lt;/p&gt;
&lt;h3 id="instance-methods"&gt;Instance Methods&lt;/h3&gt;
&lt;p&gt;인스턴스 메소드는 특정 클래스, 스트럭처, 열거형에 속하는 함수이다. 인스턴스 프로퍼티에 접근, 수정하는 방법을 제공하거나 인스턴스의 목적에 맞는 기능을 제공하여 인스턴스가 기능을 가지게 한다. 인스턴스 메소드는 함수와 똑같은 구문을 사용한다.&lt;/p&gt;
&lt;p&gt;인스턴스 메소드는 자신이 선언되어 있는 타입의 인스턴스 메소드나 타입에 암시적으로 접근 권한을 가지고 있다. 인스턴스 메소드는 자신이 선언되어 있는 타입의 인스턴스에서만 호출할 수 있으며, 밖에서 독립적으로 사용할 수 없다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Methods (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-15-methods-2/</link><pubDate>Tue, 06 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-15-methods-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="type-methods"&gt;Type Methods&lt;/h3&gt;
&lt;p&gt;이전에 설명했던 인스턴스 메소드는 특정 타입의 인스턴스가 호출한다. 타입 그 자체에 연관된 메소드는 타입 메소드라고하며, func 키워드 앞에 static 키워드를 작성하여 타입 메소드임을 나타낸다. 클래스는 서브클래스가 타입 메소드를 오버라이드 할 수 있도록 class 키워드를 대신 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;타입 메소드는 인스턴스 메소드처럼 닷 구문을 통해서 호출되지만, 인스턴스가 아닌 타입을 통해서 호출해야 한다. 다음은 클래스 SomeClass가 타입 메소드를 호출하는 예시이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;func&lt;/span&gt; &lt;span class="n"&gt;someTypeMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// type method implementation goes here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;SomeClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;someTypeMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;타입 메소드의 본문에서 self 프로퍼티는 타입의 인스턴스가 아닌 타입 자체를 뜻한다. 따라서 인스턴스 메소드처럼 이를 통해 타입 프로퍼티와 타입 메소드 프로퍼티를 구분할 수 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Subscripts (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-16-subscripts-1/</link><pubDate>Wed, 07 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-16-subscripts-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="subscripts"&gt;Subscripts&lt;/h2&gt;
&lt;p&gt;클래스, 스트럭처, 열거형은 컬렉션, 리스트, 시퀀스에서 요소에 접근할 때 사용하는 서브스크립트를 정의할 수 있다. 서브스크립트는 별도의 메소드 없이 인덱스로 값을 설정하거나 검색할 수 있다. 예를 들면, 배열 인스턴스에서 요소에 접근할 때, someArray[index]와 같이 사용하고, 딕셔너리에서 someDictionary[key]처럼 사용하는 것이 서브스크립트다.&lt;/p&gt;
&lt;p&gt;하나의 타입에 여러 개의 서브스크립트를 정의할 수 있다. 이러한 경우에는 서브스크립트에 전달되는 인덱스의 타입에 따라 적절한 서브스크립트가 선택된다. 또한 서브스크립트는 단일 차원으로 한정되지 않고, 다수의 파라미터를 받는 서브스크립트를 정의할 수 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Subscripts (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-17-subscripts-2/</link><pubDate>Wed, 07 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-17-subscripts-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="subscript-options"&gt;Subscript Options&lt;/h3&gt;
&lt;p&gt;서브스크립트는 파라미터의 수와 타입에 제한없이 받을 수 있으며, 리턴 값도 타입에 제한이 없다.&lt;/p&gt;
&lt;p&gt;함수처럼 서브스크립트는 가변 파라미터를 받고, 디폴트 값을 설정해줄 수 있다. 그러나 함수와 다르게 in-out 파라미터는 사용할 수 없다.&lt;/p&gt;
&lt;p&gt;클래스나 스트럭처는 필요한 수만큼 서브스크립트를 제공할 수 있고, 대괄호 안에 전달된 값의 타입에 따라서 적합한 서브스크립트를 추론한다. 서브스크립트를 여러개 정의하는 것을 &lt;em&gt;서브스크립트 오버로딩&lt;/em&gt; 이라고도 한다.&lt;/p&gt;
&lt;p&gt;서브스크립트는 하나의 파라미터를 받는 것이 일반적이지만, 필요한 경우 여러개의 파라미터를 받도록 정의할 수도 있다. 아래의 예시는 Double 타입 2차원 행렬을 나타내는 Matrix 스트럭처를 정의한다. Matrix 스트럭처의 서브스크립트는 두 개의 정수 파라미터를 받는다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Inheritance (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-18-inheritance-1/</link><pubDate>Thu, 08 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-18-inheritance-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="inheritance"&gt;Inheritance&lt;/h2&gt;
&lt;p&gt;클래스는 메소드, 프로퍼티등 클래스의 특성들을 다른 클래스에서 상속 받을 수 있다. 한 클래스가 다른 클래스로부터 상속을 받았을 상속 받은 클래스를 &lt;em&gt;서브클래스&lt;/em&gt; 라고 하고, 상속 해준 클래스를 &lt;em&gt;슈퍼클래스&lt;/em&gt; 라고 한다. 상속은 클래스가 다른 타입들과 구별되는 중요한 특성이다.&lt;/p&gt;
&lt;p&gt;스위프트에서 서브클래스는 슈퍼클래스의 메소드, 프로퍼티, 서브스크립트를 접근하고, 호출할 수 있다. 그리고 이러한 메소드, 프로퍼티, 서브스크립트를 오버라이딩 하여 자신에 적합하게 동작을 수정할 수도 있다. 스위프트는 오버라이드한 정의가 슈퍼 클래스의 정의에 매치되는지 확인함으로써 오버라이드가 정확하게 되도록 도와준다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Inheritance (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-19-inheritance-2/</link><pubDate>Thu, 08 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-19-inheritance-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="overriding"&gt;Overriding&lt;/h3&gt;
&lt;p&gt;서브클래스는 상속 받을 수 있는 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트에 자신만의 커스텀 구현을 할 수 있다. 이것을 &lt;em&gt;오버라이딩&lt;/em&gt; 이라고 한다.&lt;/p&gt;
&lt;p&gt;상속될 수 있는 특성을 오버라이드 하려면, 오버라이드를 하고 있는 정의 앞에 override 키워드를 붙인다. 이렇게 하면 실수로 중복 정의를 한 것이 아닌 오버라이드 했다는 것을 명확하게 보여줄 수 있다. 실수로 오버라이드 하는 것은 예측하지 못한 결과를 가져온다. 따라서 override 키워드 없이 오버라이드를 하면 컴파일할 때 에러로 검출된다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Initialization (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-20-initialization-1/</link><pubDate>Tue, 13 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-20-initialization-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="initialization"&gt;Initialization&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;이니셜라이제이션(Initialization)&lt;/em&gt; 은 클래스, 스트럭처, 열거형의 인스턴스를 사용하기 위해 준비하는 프로세스다. 이 프로세스는 인스턴스의 각 저장 프로퍼티에 초기 값을 설정하고, 인스턴스가 사용될 준비가 되기 전에 필요한 초기 설정을 하는 작업이 포함된다.&lt;/p&gt;
&lt;p&gt;이니셜라이제이션은 특정 타입의 새로운 인스턴스를 만들기 위해 호출하는 특별한 메소드인 이니셜라이저를 정의함으로써 구현할 수 있다. Objective-C의 이니셜라이저와 다르게 스위프트의 이니셜라이저는 값을 리턴하지 않는다. 이니셜라이저의 가장 중요한 역할은 새 인스턴스가 처음으로 사용되기 전에 정확하게 초기화 되는 것을 보장하는 것이다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Initialization (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-21-initialization-2/</link><pubDate>Wed, 14 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-21-initialization-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="default-initializers"&gt;Default Initializers&lt;/h3&gt;
&lt;p&gt;스위프트는 모든 프로퍼티에 디폴트 값을 제공하며, 이니셜라이저를 하나도 가지고 있지 않은 클래스나 스트럭처에게 &lt;em&gt;디폴트 이니셜라이저&lt;/em&gt; 를 제공한다. 디폴트 이니셜라이저는 모든 프로퍼티가 디폴트 값으로 설정된 새로운 인스턴스를 만든다.&lt;/p&gt;
&lt;p&gt;이 예시는 쇼핑 리스트에 있는 품목의 이름, 수량, 구매 여부를 캡슐화한 ShoppingListItem 클래스를 정의한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShoppingListItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;quantity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;purchased&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ShoppingListItem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;ShoppingListItem 클래스의 모든 프로퍼티가 디폴트 값을 가지고 있고, 슈퍼클래스가 없는 베이스 클래스이기 때문에, ShoppingListItem 클래스는 자동적으로 디폴트 이니셜라이저를 가지게 된다.(name 프로퍼티는 옵셔널 프로퍼티이기 때문에 디폴트 값을 주지 않아도 자동적으로 nil이 자동적으로 디폴트 값이 된다) 위의 예시에서 디폴트 이니셜라이저를 이용해 ShoppingListItem의 새 인스턴스를 만든다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Initialization (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-22-initialization-3/</link><pubDate>Fri, 16 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-22-initialization-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h4 id="initializer-inheritance-and-overriding"&gt;Initializer Inheritance and Overriding&lt;/h4&gt;
&lt;p&gt;Objective-C의 서브클래스와 다르게 스위프트의 서브클래스는 기본적으로 슈퍼클래스의 이니셜라이저를 상속받지 않는다. 이러한 스위프트의 접근방식은 슈퍼클래스에서 상속받은 간단한 이니셜라이저가 서브클래스의 완전히 초기화 되지 않은 새 인스턴스를 만드는 것을 방지한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
슈퍼클래스의 이니셜라이저는 특정 상황에서는 상속되지만, 안전하고 적합할 때만 상속된다. 자세한 내용은 아래의 Automatic Initializer Inheritance에 나온다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;서브클래스가 하나 이상의 슈퍼클래스와 동일한 이니셜라이저를 가지고 있으려면, 서브클래스 내부에 직접 구현하여 제공할 수 있다.&lt;/p&gt;
&lt;p&gt;슈퍼클래스의 데지그네이티드 이니셜라이저와 일치하는 이니셜라이저를 서브클래스에 작성할 때, 그 데지그네이티드 이니셜라이저의 오버라이드를 효과적으로 제공할 수 있다. 그러므로 반드시 서브클래스의 이니셜라이저의 정의 앞에 override를 작성해야 한다. 자동적으로 제공된 디폴트 이니셜라이저라도 마찬가지다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Initialization (4)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-23-initialization-4/</link><pubDate>Sat, 17 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-23-initialization-4/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="failable-initializers"&gt;Failable Initializers&lt;/h3&gt;
&lt;p&gt;이니셜라이제이션이 실패할 수 있는 클래스, 스트럭처, 열거형을 정의하는 것이 유용하게 쓰일 때가 있다. 유효하지 않은 파라미터 값, 필요한 외부 리소스의 부재, 이니셜라이제이션이 실패해야하는 조건 등으로 이러한 실패를 트리거할 수 있다.&lt;/p&gt;
&lt;p&gt;실패할 수 있는 이니셜라이제이션 조건을 다루기 위해서는, 하나 이상의 실패 가능한(failable) 이니셜라이저를 클래스, 스트럭처, 열거형의 정의의 한 파트로 정의한다. 실패 가능한 이니셜라이저는 init 키워드 뒤에 ?를 붙여서 표시할 수 있다.(init?)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
동일한 타입과 이름을 가진 파라미터들로 실패 가능한 이니셜라이저와 실패 불가능한 이니셜라이저를 동시에 정의할 수 없다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Deinitialization</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-24-deinitialization/</link><pubDate>Sun, 18 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-24-deinitialization/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="deinitialization"&gt;Deinitialization&lt;/h2&gt;
&lt;p&gt;디이니셜라이저는 클래스의 인스턴스가 할당 해제되기 전에 직전에 호출된다. 이니셜라이저가 init 키워드를 사용하여 작성하는 것 처럼, deinit 키워드를 사용하여 디이니셜라이저를 작성할 수 있다. 디이니셜라이저는 클래스 타입에만 사용 가능하다.&lt;/p&gt;
&lt;h3 id="how-deinitialization-works"&gt;How Deinitialization Works&lt;/h3&gt;
&lt;p&gt;스위프트는 인스턴스가 더 이상 필요하지 않을때, 자동적으로 할당을 해제해여 리소스를 확보한다. 스위프트는 automatic reference counting (ARC)를 통해 메모리를 관리한다. 일반적으로 인스턴스가 할당 해제될때 수동적으로 처리를 해줄 필요가 없다. 하지만 자체적인 리소스로 작업을 할 경우에는, 수동으로 추가적인 처리를 해줘야 하는 경우가 있다. 예를 들면, 파일을 열고 거기에 데이터를 작성하는 커스텀 클래스가 있을 때, 그 클래스의 인스턴스가 할당 해제되기 전에 파일을 먼저 닫아줘야 한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Optional Chaining (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-25-optional-chaining-1/</link><pubDate>Mon, 19 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-25-optional-chaining-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="optional-chaining"&gt;Optional Chaining&lt;/h2&gt;
&lt;p&gt;옵셔널 체이닝은 nil일 수도 있는 프로퍼티, 메소드, 서브스크립트를 호출하고 쿼리하는 프로세스이다. 만약 옵셔널에 값이 있다면, 프로퍼티, 메소드, 서브스크립트 호출은 성공하고, nil이라면 프로퍼티, 메소드, 서브스크립트 호출은 nil을 리턴한다. 다수의 쿼리를 하나의 체인으로 엮을 수 있으며, 그중 하나라도 nil값을 가진다면 전체적인 체인은 안전하게 실패한다.&lt;/p&gt;
&lt;h3 id="optional-chaining-as-an-alternative-to-forced-unwrapping"&gt;Optional Chaining as an Alternative to Forced Unwrapping&lt;/h3&gt;
&lt;p&gt;호출하고자 하는 프로퍼티, 메소드, 서브스크립트가 nil이 아니라면, 옵셔널 값 뒤에 물음표(?)를 붙여 옵셔널 체이닝을 특정할 수 있다. 이것은 옵셔널 값 뒤에 느낌표(!)를 붙여 강제 언래핑을 하는 것과 매우 비슷하다. 가장 큰 차이점은, 옵셔널 체이닝은 만약 옵셔널이 nil이라면 안전하게 실패하고, 강제 언래핑은 옵셔널이 nil이면 런타임 에러를 발생시킨다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Optional Chaining (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-26-optional-chaining-2/</link><pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-26-optional-chaining-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="linking-multiple-levels-of-chaining"&gt;Linking Multiple Levels of Chaining&lt;/h3&gt;
&lt;p&gt;다중 레벨의 옵셔널 체이닝을 서로 연결하여 모델 내부의 프로퍼티, 메소드, 서브스크립트로 깊게 내려갈 수 있다. 하지만 다중 레벨 옵셔널 체이닝은 리턴된 값에 옵셔널 단계를 증가시키지 않는다.(주: 옵셔널 체이닝을 하면 항상 옵셔널 값이 리턴되는데, 옵셔널 체이닝 여러개를 합친다 해서 이중 옵셔널, 삼중 옵셔널이 되지 않는다는 뜻)&lt;/p&gt;
&lt;p&gt;다른말로 설명하자면:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;옵셔널이 아닌 값을 검색하려고 시도하면, 옵셔널 체이닝 때문에 옵셔널 값이 된다.&lt;/li&gt;
&lt;li&gt;옵셔널 값을 검색하려고 시도하면, 체이닝 때문에 옵셔널이 추가되지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그러므로:&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Error Handling (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-27-error-handling-1/</link><pubDate>Wed, 21 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-27-error-handling-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="error-handling"&gt;Error Handling&lt;/h2&gt;
&lt;p&gt;에러 핸들링은 프로그램이 에러 상황에서 응답하고 회복하는 프로세스이다. 스위프트는 런타임에 복구 가능한 에러를 던지고(throwing), 포착하고(catching), 전파하고(propagating), 조정하는(manipulating)데 최적화된 지원을 해준다.&lt;/p&gt;
&lt;p&gt;일부 연산들은 항상 실행을 마치거나 의미있는 결과를 생성하는 것을 보장하지 않는다. 옵셔널은 값의 부재를 나타내는 사용되자만, 연산이 실패한 경우에는 코드가 그에 응답할 수 있도록 실패한 이유를 아는 것이 유용하다.&lt;/p&gt;
&lt;p&gt;예를 들면, 디스크에 저장되어있는 파일을 읽고 처리하는 작업을 생각해보자. 이 작업에는 특정 경로에 없는 파일을 포함하거나, 파일에 대한 읽기 권한이 없거나, 파일을 호환 가능한 포맷으로 인코딩 하지 못하는 등의 수많은 실패 요소들이 있다. 이러한 상황들을 구분하면, 프로그램이 해결할 수 있는 에러는 해결하고, 해결 불가능한 에러는 사용자들에게 알릴 수 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Error Handling (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-28-error-handling-2/</link><pubDate>Thu, 22 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-28-error-handling-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h4 id="handling-errors-using-do-catch"&gt;Handling Errors Using Do-Catch&lt;/h4&gt;
&lt;p&gt;do-catch 문을 사용하면 코드 블록을 실행해서 에러를 처리할 수 있다. 에러가 do절에서 발생하면, 그 에러를 처리할 수 있는 catch절과 매치된다.&lt;/p&gt;
&lt;p&gt;다음은 do-catch문의 일반적인 형태이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;statements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;catch절 뒤에 (에러의) 패턴을 작성하여, 그 catch절이 처리할 수 있는 에러를 나타낸다. catch절이 패턴을 가지고 있지 않다면, 이 catch절은 모든 에러와 매치될 수 있으며, error라는 이름을 가진 로컬 상수에 바인딩 된다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Concurrency (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-29-concurrency-1/</link><pubDate>Fri, 23 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-29-concurrency-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="concurrency"&gt;Concurrency&lt;/h2&gt;
&lt;p&gt;스위프트는 구조화된 방식의 비동기적이고 병렬 수행되는 코드 작성에 대한 지원이 내장되어있다. &lt;em&gt;비동기(Asynchronuous)&lt;/em&gt; 코드는 일시중단 되었다가 나중에 재개할 수 있지만, 한번에 프로그램의 한 부분만 실행된다. 프로그램에서 코드를 중단하고 재개하면 네트워크에서 데이터를 불러오거나, 파일 파싱과 같은 긴 시간이 걸리는 작업을 계속 진행하면서 UI 업데이트와 같은 짧은 시간이 걸리는 작업을 계속할 수 있다. &lt;em&gt;병렬 코드(Parallel code)&lt;/em&gt; 는 동시에 실행되는 코드들을 의미한다 — 예를 들어 4코어 프로세서를 가진 컴퓨터는 각각의 코어가 코드 하나씩을 실행하게 하여, 네 개의 코드를 동시에 실행할 수 있다. 병렬과 비동기 코드를 사용하는 프로그램은 한번에 여러 작업을 수행하고, 외부 시스템을 기다리는 작업을 일시 중단한다. 이 챕터의 나머지 부분에서 용어 &lt;em&gt;동시성(concurrency)&lt;/em&gt; 는 비동기 및 병렬 코드를 지칭한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Concurrency (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-30-concurrency-2/</link><pubDate>Mon, 26 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-30-concurrency-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="asynchronous-sequences"&gt;Asynchronous Sequences&lt;/h3&gt;
&lt;p&gt;이전 섹션의 listPhotos(inGallery:) 함수는 모든 배열의 원소들이 준비된 후, 비동기적으로 전체 배열을 리턴한다. 다른 접근 방법으로는 &lt;em&gt;비동기 시퀀스(asynchronous Sequence)&lt;/em&gt; 를 사용하여 컬렉션의 요소 하나를 한 번에 하나씩 기다리는 것이다. 다음은 비동기 시퀀스를 반복하는 모습이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;handle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FileHandle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;standardInput&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;일반적인 for-in 루프를 사용하는 대신에, 위의 예시는 for 다음에 await를 작성한다. 비동기 함수나 메소드를 호출할 때 처럼 await를 쓰는 것은 정지 가능한 지점을 나타낸다. for-await-in 루프는 각 반복이 시작될 때, 다음 원소가 준비될 때 까지 기다리는 동안 실행을 정지한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Concurrency (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-31-concurrency-3/</link><pubDate>Mon, 26 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-31-concurrency-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="actors"&gt;Actors&lt;/h3&gt;
&lt;p&gt;태스크를 이용하여 프로그램을 분리된 동시성 조각으로 나눌 수 있다. 태스크는 서로 독립적이기 때문에 동시에 실행되어도 안전하다. 하지만 가끔씩 태스크들 사이에 정보를 공유해야 하는 경우가 있다. 액터는 동시성 코드 사이에 정보를 안전하게 공유하도록 해준다.&lt;/p&gt;
&lt;p&gt;클래스처럼 액터는 레퍼런스 타입이다. 따라서 Classes Are Reference Types에서 값 타입과 레퍼런스 타입을 비교한 것이 액터에도 적용된다. 클래스와 다르게, 액터는 한번에 하나의 작업만 변경 가능한 상태(mutable state)에 접근하도록 허용하기 때문에, 여러 태스크가 액터의 한 인스턴스에 상호작용하는 것을 안전하게 해준다. 예를 들어 다음은 온도를 기록하는 액터이다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Macro (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-32-macro-1/</link><pubDate>Thu, 14 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-32-macro-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;p&gt;매크로는 컴파일할 때 소스 코드를 변환하여, 반복적인 코드를 직접 작성하지 않게 해준다. 컴파일하는 동안, Swift는 평상시처럼 코드를 빌드하기 전에 매크로들을 확장한다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/the-swift-programming-language-32-macro-1/image-002-optimized-image.webp"&gt;&lt;p&gt;매크로를 확장하는 것은 항상 추가하는(additive) 작업이다: 매크로는 새로운 코드를 더하지만, 기존에 존재하는 코드를 삭제하거나 수정하지 않는다.&lt;/p&gt;
&lt;p&gt;매크로 입력과, 매크로 확장의 출력 둘 다 구문적으로 유효한 Swift 코드인지 체크된다. 마찬가지로, 매크로에 전달되는 값과 매크로로 생성된 코드 안의 값이 정확한 타입인지 검사된다. 추가적으로, 매크로를 확장할 때 구현부에서 에러를 마주치면, 컴파일러는 이를 컴파일 에러로 처리한다. 이러한 보장은 매크로를 사용하는 코드를 더 쉽게 이해하게 해주고, 매크로를 잘못 사용하거나 매크로의 구현에 버그가 있는 이슈들을 더 쉽게 알아차리게 해준다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Macro (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-33-macro-2/</link><pubDate>Fri, 15 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-33-macro-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="macro-expansion"&gt;Macro Expansion&lt;/h3&gt;
&lt;p&gt;매크로를 사용한 Swift 코드를 빌드 할 때, 코드를 확장하기 위해 매크로의 구현을 불러오게 된다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/the-swift-programming-language-33-macro-2/image-002-optimized-image.webp"&gt;&lt;p&gt;구체적으로 Swift는 다음과 같은 방법으로 매크로를 확장한다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;컴파일러가 코드를 읽어, 구문의 in-memory 표현을 만든다.&lt;/li&gt;
&lt;li&gt;컴파일러가 이 in-memory 표현의 일부를 매크로를 확장시키는 매크로 구현부에 보낸다.&lt;/li&gt;
&lt;li&gt;컴파일러가 매크로 호출을 확장된 형태로 대체한다.&lt;/li&gt;
&lt;li&gt;컴파일러가 확장된 소스 코드를 사용하여 컴파일을 계속 진행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;구체적인 단계들을 살펴보기 위해, 다음을 생각해보자:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;magicNumber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="n"&gt;fourCharacterCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;ABCD&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;#fourCharacterCode&lt;/code&gt; 매크로는 4개의 캐릭터로 구성된 문자열을 받아, 그 문자열의 ASCII 값들을 이어 붙인 32비트 언사인드 인티저를 리턴한다. 일부 파일 포맷은 데이터를 식별하기 위해 이런 형태의 인티저를 사용하는데, 컴팩트 하면서도 디버거에서 읽을 수 있기 때문이다. 아래의 Implementing a Macro 섹션에서 이 매크로를 구현하는 방법을 보여준다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Type Casting</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-34-type-casting/</link><pubDate>Tue, 27 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-34-type-casting/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="type-casting"&gt;Type Casting&lt;/h2&gt;
&lt;p&gt;타입 캐스팅(Type casting)은 인스턴스의 타입을 체크하거나, 해당 클래스가 소속된 계층의 다른 슈퍼클래스나 서브클래스로 취급하는 방법이다.&lt;/p&gt;
&lt;p&gt;스위프트의 타입 캐스팅은 is 혹은 as 연산자로 구현된다. 이 두 연산자는 값의 타입을 체크하거나, 다른 타입으로 값을 캐스트하는 간단하고 표현적인 방법을 제공한다.&lt;/p&gt;
&lt;p&gt;타입이 프로토콜을 준수하고 있는지 여부를 확인하기 위해 타입 캐스팅을 사용할 수도 있다.&lt;/p&gt;
&lt;h3 id="defining-a-class-hierarchy-for-type-casting"&gt;Defining a Class Hierarchy for Type Casting&lt;/h3&gt;
&lt;p&gt;클래스와 서브클래스들의 계층에서 특정 클래스의 타입을 체크하거나 그 클래스의 인스턴스를 같은 계층의 다른 클래스로 캐스트할 때 사용할 수 있다. 아래의 코드 세 개는 앞으로 나올 예시들에서 쓰일 클래스의 계층과, 이 클래스들의 인스턴스를 담고 있는 배열을 정의한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Nested Types</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-35-nested-types/</link><pubDate>Wed, 28 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-35-nested-types/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="nested-types"&gt;Nested Types&lt;/h2&gt;
&lt;p&gt;열거형은 특정 클래스나 스트럭처의 기능을 지원하도록 자주 생성된다. 비슷한 이유로, 클래스나 스트럭처를 복잡한 컨텍스트 내부에서 순수하게 유틸 용도로 사용하기 위해 정의할 수도 있다. 이를 위해 스위프트에서는 &lt;em&gt;중첩 타입(nested types)&lt;/em&gt; 을 정의할 수 있다. 중첩 타입을 지원하는 타입의 정의 내부에서 중첩 열거형, 클래스, 스트럭처를 중첩시킬 수 있다.&lt;/p&gt;
&lt;h3 id="nested-types-in-action"&gt;Nested Types in Action&lt;/h3&gt;
&lt;p&gt;아래의 예시는 블랙잭 카드 게임에서 사용하는 플레잉 카드를 모델링하는 BlackjackCard라는 스트럭처를 정의한다. BlackjackCard 스트럭처는 두 개의 중첩 열거형 타입 Suit와 Rank를 가지고 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Extensions (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-36-extensions-1/</link><pubDate>Thu, 29 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-36-extensions-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="extensions"&gt;Extensions&lt;/h2&gt;
&lt;p&gt;익스텐션(Extensions)은 이미 존재하는 클래스, 스트럭처, 열거형, 프로토콜에 새로운 기능을 추가한다. 이는 원본 코드에 접근할 수 없는 타입(&lt;em&gt;retroactive modeling&lt;/em&gt; 라고도 함)에 대한 확장도 가능하다.&lt;/p&gt;
&lt;p&gt;스위프트의 익스텐션은 다음과 같은 행동을 할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;컴퓨티드 인스턴스 프로퍼티 혹은 컴퓨티드 타입 프로퍼티 추가&lt;/li&gt;
&lt;li&gt;인스턴스 메소드 혹은 타입 메소드 정의&lt;/li&gt;
&lt;li&gt;새로운 이니셜라이저 제공&lt;/li&gt;
&lt;li&gt;서브스크립트 정의&lt;/li&gt;
&lt;li&gt;새로운 중첩 타입 정의 및 사용&lt;/li&gt;
&lt;li&gt;이미 존재하는 타입이 프로토콜 준수하도록 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;스위프트에서는 프로토콜도 확장(extend)하여 요구사항 구현을 제공하거나, 그 프로토콜을 준수하고 있는 타입들이 사용할 수 있는 추가 기능을 제공할 수도 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Extensions (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-37-extensions-2/</link><pubDate>Thu, 29 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-37-extensions-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="methods"&gt;Methods&lt;/h3&gt;
&lt;p&gt;익스텐션은 이미 존재하는 타입에 새 인스턴스 메소드와 타입 메소드를 추가할 수 있다. 다음의 예시는 새 인스턴스 메소드 repetitions을 Int 타입에 추가한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;repetitions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;repetitions(task:) 메소드는 하나의 () -&amp;gt; Void 타입 아규먼트를 받는다.&lt;/p&gt;
&lt;p&gt;이 익스텐션을 정의한 후에는 repetitions(task:)메소드를 어떠한 정수에서도 호출할 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mf"&gt;3.&lt;/span&gt;&lt;span class="n"&gt;repetitions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Hello!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Hello!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Hello!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id="mutating-instance-methods"&gt;Mutating Instance Methods&lt;/h4&gt;
&lt;p&gt;익스텐션에서 추가된 인스턴스 메소드는 인스턴스 자체를 수정(mutate)할 수도 있다. self나 self의 프로퍼티를 수정하는 스트럭처나 열거형은 메소드도 기존 구현의 뮤테이팅 메소드처럼 반드시 mutating으로 지정되어야 한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Protocols (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-38-protocols-1/</link><pubDate>Fri, 30 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-38-protocols-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="protocols"&gt;Protocols&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;프로토콜(protocol)&lt;/em&gt; 은 특정 작업이나 기능에 적합한 메소드, 프로퍼티, 기타 요구사항에 대한 청사진을 정의한다. 프로토콜은 해당 요구사항들을 실제로 구현하기 위해 클래스, 스트럭처, 열거형에서 도입할 수 있다. 프로토콜의 요구사항들을 만족하는 타입을 프로토콜을 &lt;em&gt;준수한다고(conform)&lt;/em&gt; 말한다.&lt;/p&gt;
&lt;p&gt;프로토콜을 준수하고 있는 타입이 반드시 구현해야하는 요구사항을 지정하는 것 외에도, 프로토콜을 확장하여 이러한 요구사항들의 일부를 구현하거나, 그 프로토콜을 준수하고 있는 타입이 사용할 수 있는 기능을 추가할 수 있다.&lt;/p&gt;
&lt;h3 id="protocol-syntax"&gt;Protocol Syntax&lt;/h3&gt;
&lt;p&gt;프로토콜은 클래스, 스트럭처, 열거형과 매우 비슷한 방법으로 정의한다:&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Protocols (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-39-protocols-2/</link><pubDate>Sat, 01 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-39-protocols-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="protocols-as-types"&gt;Protocols as Types&lt;/h3&gt;
&lt;p&gt;프로토콜은 어떠한 기능도 실제로 구현하지는 않는다. 하지만 코드에서 프로토콜을 타입으로 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;프로토콜을 타입으로 사용하는 가장 일반적인 방법은 프로토콜을 제네릭 제약조건(generic constraint)로 사용하는 것이다. 제네릭 제약조건이 있는 코드는 프로토콜을 준수하는 모든 타입에서 사용할 수 있으며, 특정 타입은 API를 사용되는 코드에서 선택된다. 예를 들어 제네릭 아규먼트를 받는 함수를 호출하면, 호출자가 타입을 선택한다.&lt;/p&gt;
&lt;p&gt;불투명한 타입(opaque type)의 코드는 프로토콜을 준수하는 일부 타입에서 동작한다. 실제 타입은 컴파일 타임에 알수 있고, API 구현은 그 타입을 선택하지만 그 타입의 식별자는 클라이언트에게 숨겨져 있다. 불투명한 타입을 사용하는 것은 추상화 레이어를 통해 API의 디테일한 구현이 유출되는 것을 방지하게 해준다. — 예를 들어, 함수의 지정된 리턴 타입을 숨기고, 리턴 값의 타입이 주어진 프로토콜을 준수한다는 것만을 보장하게 한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Protocols (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-40-protocols-3/</link><pubDate>Sun, 02 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-40-protocols-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="adding-protocol-conformance-with-and-extension"&gt;Adding Protocol Conformance with and Extension&lt;/h3&gt;
&lt;p&gt;새로운 프로토콜을 도입하고 준수하기 위해 이미 존재하는 타입을 확장할 수 있다. 그 타입의 원본 소스코드에 접근하지 못하더라도 가능하다. 익스텐션은 이미 존재하는 타입에 새로운 프로퍼티, 메소드, 서브스크립트를 추가할 수 있으므로, 프로토콜에서 요구하는 모든 요구사항들을 추가할 수 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;br&gt;
타입의 이미 존재하는 인스턴스는 인스턴스의 타입의 익스텐션에 프로토콜 준수가 추가되었을 때, 자동적으로 프로토콜을 준수하게 된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;예를 들어, TextRespresentable 프로토콜은 텍스트로 표현할 수 있는 방법이 있는 모든 타입에서 구현 가능하다:&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Protocols (4)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-41-protocols-4/</link><pubDate>Mon, 03 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-41-protocols-4/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="protocol-composition"&gt;Protocol Composition&lt;/h3&gt;
&lt;p&gt;하나의 타입이 여러개의 프로토콜을 동시에 준수하도록 하는 것이 유용할 때가 있다. &lt;em&gt;프로토콜 구성(protocol composition)&lt;/em&gt; 을 통해 여러 개의 프로토콜을 하나의 프로토콜로 결합할 수 있다. 프로토콜 구성은 내부에 있는 모든 프로토콜의 요구사항을 결합한 임시 로컬 프로토콜을 정의한 것처럼 동작한다. 하지만 프로토콜 구성은 어떠한 새로운 프로토콜 타입도 정의하지 않는다.&lt;/p&gt;
&lt;p&gt;프로토콜 구성은 SomeProtocol &amp;amp; AnotherProtocol의 형태를 가진다. 앰퍼샌드로 구분하여 필요한 수 만큼 프로토콜을 나열할 수 있다. 프로토콜 리스트에 추가로 프로토콜 구성은 필요로 하는 슈퍼클래스로 지정하기 위해 하나의 클래스 타입을 포함할 수도 있다.(주: 프로토콜 구성을 준수하려면 특정 클래스의 서브클래스이어야 할 때, 슈퍼클래스도 그 프로토콜 구성 내부에 포함시킨다.)&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Protocols (5)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-42-protocols-5/</link><pubDate>Tue, 04 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-42-protocols-5/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="protocol-extensions"&gt;Protocol Extensions&lt;/h3&gt;
&lt;p&gt;프로토콜은 메소드, 이니셜라이저, 서브스크립트, 컴퓨티드 프로퍼티를 해당 프로퍼티를 준수하는 타입들에게 제공하도록 확장될 수 있다. 이는 각 타입의 개별 준수나 전역 함수가 아니라 프로토콜 스스로 동작을 정의할 수 있게 해준다.&lt;/p&gt;
&lt;p&gt;예를 들어, RandomNumberGenerator 프로토콜은 random() 메소드 요구사항의 결과값을 사용하여 랜덤 Bool 값을 리턴하는 randomBool() 메소드를 제공하도록 확장될 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;RandomNumberGenerator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;randomBool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;프로토콜의 익스텐션을 만들면, 해당 프로토콜을 준수하는 모든 타입은 추가적인 수정 없이 모든 이러한 메소드 구현을 자동적으로 얻게 된다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Generics (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-43-generics-1/</link><pubDate>Tue, 01 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-43-generics-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="generics"&gt;Generics&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;제네릭 코드(Generic code)&lt;/em&gt; 는 정의한 요구사항을 만족하는 모든 타입과 함께 작업할 수 있는 유연하고 재사용성 높은 함수나 타입을 작성하게 해준다. 코드의 중복을 피하고, 의도를 추상적이고 명확한 방법으로 표현할 수 있다.&lt;/p&gt;
&lt;p&gt;제네릭은 스위프트의 강력한 특징 중 하나이며, 많은 스위프트의 표준 라이브러리는 제네릭 코드로 빌드 되어있다. 사실 인지하지 못했어도 Language Guide 내내 제네릭 코드를 사용했다. 예를 들어, 스위프트의 &lt;code&gt;Array&lt;/code&gt;와 &lt;code&gt;Dictionary&lt;/code&gt; 타입은 둘 다 제네릭 컬렉션이다. &lt;code&gt;Int&lt;/code&gt; 값을 저장하는 배열, &lt;code&gt;String&lt;/code&gt; 값을 저장하는 배열, 혹은 스위프트에서 만들 수 있는 어떠한 다른 타입이라도 저장하는 배열 등을 생성할 수 있다. 비슷하게, 어떤 타입이든지 간에 특정한 타입을 저장하는 딕셔너리를 만들 수 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Generics (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-44-generics-2/</link><pubDate>Wed, 02 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-44-generics-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="generic-types"&gt;Generic Types&lt;/h3&gt;
&lt;p&gt;제네릭 함수와 다르게, 스위프트는 제네릭 타입도 정의할 수 있게 해준다. 이는 &lt;code&gt;Array&lt;/code&gt;나 &lt;code&gt;Dictionary&lt;/code&gt;처럼 모든 타입과 함께 작업할 수 있는 커스텀 클래스, 스트럭처, 열거형이다.&lt;/p&gt;
&lt;p&gt;이 섹션은 스택이라는 제네릭 컬렉션 타입을 작성하는 방법을 보여준다. 스택은 배열과 비슷하게 순서가 있는 값들의 집합이다, 하지만 스위프트의 &lt;code&gt;Array&lt;/code&gt; 타입보다 더 제한된 작업을 한다. 배열은 배열의 어느 위치에서나 값을 삽입하거나 제거할 수 있지만, 스택은 컬렉션의 끝 부분에서만 삽입(&lt;em&gt;pushing&lt;/em&gt;)이나 삭제(&lt;em&gt;popping&lt;/em&gt;)을 할 수 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Generics (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-45-generics-3/</link><pubDate>Fri, 04 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-45-generics-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="type-constraints"&gt;Type Constraints&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;swapTwoValues(_:_:)&lt;/code&gt; 함수와 &lt;code&gt;Stack&lt;/code&gt; 타입은 어떠한 타입으로도 작업할 수 있다. 하지만 특정한 &lt;em&gt;타입 제약조건(type constraints)&lt;/em&gt; 을 강제하여 제네릭 함수나 제네릭 타입이 사용할 수 있는 타입을 지정하는 것이 유용할 때가 있다. 타입 제약조건은 타입 파라미터가 특정한 클래스를 상속 받거나, 특정 프로토콜을 준수해야 하도록 지정한다.&lt;/p&gt;
&lt;p&gt;예를 들어, 스위프트의 &lt;code&gt;Dictionary&lt;/code&gt; 타입은 딕셔너리의 키로 사용할 수 있는 타입에 제한을 둔다. 딕셔너리의 키로 사용될 타입은 반드시 &lt;em&gt;hashable&lt;/em&gt; 해야한다. 즉, 스스로를 유니크하게 구분할 수 있어야 한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Generics (4)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-46-generics-4/</link><pubDate>Mon, 07 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-46-generics-4/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="associated-types"&gt;Associated Types&lt;/h3&gt;
&lt;p&gt;프로토콜을 정의할때, 프로토콜의 정의의 일부로 하나 혹은 그 이상의 &lt;em&gt;연관 타입(associated type)&lt;/em&gt; 을 선언하는 것이 유용할 때가 있다. 연관 타입은 프로토콜의 일부로 사용되는 타입에게 플레이스홀더 이름을 부여한다. 해당 연관 타입이 될 실제 타입은 프로토콜이 적용될 때 까지 지정되지 않는다. 연관 타입은 associatedtype 키워드로 특정할 수 있다.&lt;/p&gt;
&lt;h3 id="associated-types-in-action"&gt;Associated types in Action&lt;/h3&gt;
&lt;p&gt;다음은 연관 타입으로 &lt;code&gt;Item&lt;/code&gt;을 선언하는 프로토콜 &lt;code&gt;Container&lt;/code&gt;의 예시이다:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;associatedtype&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;subscript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;Container&lt;/code&gt; 프로토콜은 모든 컨테이너가 반드시 제공해야할 세 개의 필수 요구사항을 정의한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Generics (5)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-47-generics-5/</link><pubDate>Tue, 08 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-47-generics-5/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="generic-where-clauses"&gt;Generic Where Clauses&lt;/h3&gt;
&lt;p&gt;타입 제약조건을 사용하면 제너럴 함수, 서브스크립트, 타입에 관련된 타입 파라미터의 요구사항을 정의할 수 있다.&lt;/p&gt;
&lt;p&gt;이는 연관 타입의 제약 조건을 정의하는데에도 유용하며, 제네릭 where 절을 정의하여 할 수 있다. 제네릭 &lt;code&gt;where&lt;/code&gt;절은 연관 타입이 반드시 특정 프로토콜을 준수하게 하거나, 특정한 타입 파라미터와 연관 타입이 반드시 같아야 함을 요구할 수 있다. 제네릭 &lt;code&gt;where&lt;/code&gt;절은 &lt;code&gt;where&lt;/code&gt; 키워드로 시작하고, 뒤에 연관 타입의 제약조건이나 타입 파라미터와 연관 타입의 동등 관계를 작성한다. 제네릭 where절은 타입이나 함수의 본문의 여는 중괄호 바로 앞에 작성한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Opaque Types (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-48-opaque-types-1/</link><pubDate>Sat, 12 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-48-opaque-types-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="opaque-and-boxed-types"&gt;Opaque and Boxed Types&lt;/h2&gt;
&lt;p&gt;스위프트는 값의 타입에 대한 상세한 정보를 숨기는 두가지 방법을 제공한다: 불투명한 타입과 박스형 프로토콜 타입이다. 타입의 정보를 숨기는 것은 모듈과 모듈을 호출하는 코드의 경계에서 유용하다, 리턴 값의 타입이 공개되지 않은 채로 유지될 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;함수나 메소드는 리턴 값의 타입 정보를 숨기기 위해 불투명한 타입을 리턴하다. 함수의 리턴 타입을 구체적으로 제공하는 대신에, 리턴 값은 값이 지원하는 프로토콜로 묘사된다. 불투명한 타입은 타입의 정체를 보존한다 — 컴파일러는 타입 정보에 대해 접근이 가능하지만, 모듈의 클라이언트들은 불가능하다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Opaque Types (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-49-opaque-types-2/</link><pubDate>Sun, 13 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-49-opaque-types-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="boxed-protocol-types"&gt;Boxed Protocol Types&lt;/h3&gt;
&lt;p&gt;박스드 프로토콜 타입은 “there exists a type T such that T conforms to the protocol” 라는 구절에서 따와 실존적 타입 &lt;em&gt;(existential type)&lt;/em&gt; 이라고도 한다. 박스드 프로토콜 타입을 만들기 위해, 프로토콜 이름 앞에 &lt;code&gt;any&lt;/code&gt;를 작성한다. 다음은 예시이다:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;VerticalShapes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Shape&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;shapes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="n"&gt;joined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;largeTriangle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Triangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;largeSquare&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;vertical&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VerticalShapes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shapes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;largeTriangle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;largeSquare&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위의 예시에서, &lt;code&gt;VerticalShapes&lt;/code&gt;는 도형들의 타입을 박스드 &lt;code&gt;Shape&lt;/code&gt; 원소들의 배열인 &lt;code&gt;[any Shape]&lt;/code&gt;로 선언한다. 배열의 각 원소들은 서로 다른 타입일 수 있지만, 반드시 &lt;code&gt;Shape&lt;/code&gt; 프로토콜을 준수해야 한다. 런타임에 유연성을 지원하기 위해, 스위프트는 필요할 때 박스(box)라는 간접적인 단계를 추가한다. 박스는 성능 코스트가 있다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Automatic Reference Counting (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-50-automatic-reference-counting-1/</link><pubDate>Tue, 15 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-50-automatic-reference-counting-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="automatic-reference-counting"&gt;Automatic Reference Counting&lt;/h2&gt;
&lt;p&gt;스위프트는 &lt;em&gt;자동 참조 카운팅&lt;/em&gt;(ARC)을 사용하여 앱의 메모리 사용량을 추적하고 관리한다. 대부분의 경우에, 스위프트에서 메모리 관리는 &amp;ldquo;그냥 작동&amp;quot;하고, 메모리 관리를 직접 할 생각을 하지 않아도 된다. ARC는 클래스 인스턴스가 더 이상 필요하지 않게 되었을 때, 자동적으로 해당 메모리를 비우게 된다.&lt;/p&gt;
&lt;p&gt;하지만, 경우에 따라 ARC는 메모리 관리를 위해 코드 내부에서의 관계**(주: 원문은 relationships between parts of your code, 코드 부분들 간의 관계)** 에 대한 정보를 요구할 때가 있다. 이 챕터는 이러한 상황들을 설명하고, 어떻게 ARC가 앱의 메모리를 관리하는지를 보여준다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Automatic Reference Counting (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-51-automatic-reference-counting-2/</link><pubDate>Wed, 16 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-51-automatic-reference-counting-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="resolving-strong-reference-cycles-between-class-instances"&gt;Resolving Strong Reference Cycles Between Class Instances&lt;/h3&gt;
&lt;p&gt;스위프트는 클래스 타입 프로퍼티로 작업할 때 강한 참조 사이클을 해결하는 두 가지 방법으로 약한 참조와 미소유 참조를 제공한다.&lt;/p&gt;
&lt;p&gt;약한 참조와 미소유 참조는 참조 사이클 내부의 한 인스턴스가 다른 인스턴스를 강하게 붙잡지 않고 참조할 수 있게 해준다. 그리고는 그 인스턴스들은 서로를 강한 참조 사이클 없이 참조할 수 있게 된다.&lt;/p&gt;
&lt;p&gt;다른 인스턴스의 수명이 더 짧을 때 약한 참조를 사용한다. — 즉 다른 인스턴스가 먼저 할당 해제되는 경우이다. 이전의 &lt;code&gt;Apartment&lt;/code&gt; 예시에서, 아파트의 라이프 사이클 중간에 거주자가 없는 것은 충분히 가능한 일이므로 약한 참조는 이러한 경우의 참조 사이클을 깨뜨리는데 적합하다. 반대로, 미소유 참조를 사용하는 것은 다른 인스턴스가 같거나 더 긴 수명을 가지고 있을때 사용한다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Automatic Reference Counting (3)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-52-automatic-reference-counting-3/</link><pubDate>Mon, 21 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-52-automatic-reference-counting-3/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h3 id="strong-reference-cycles-for-closures"&gt;Strong Reference Cycles for Closures&lt;/h3&gt;
&lt;p&gt;두 클래스 인스턴스의 프로퍼티들이 서로를 강한 참조하면서 강한 참조 사이클이 만들어지는지를 이전에 보았고, 약한 참조와 미소유 참조가 이러한 강한 참조 사이클을 깨뜨리는 것도 보았다.&lt;/p&gt;
&lt;p&gt;강한 참조 사이클은 클래스의 인스턴스에 클로저를 할당하고, 해당 클로저의 본문에서 그 인스턴스를 캡처할때도 발생한다. 이러한 캡처는 &lt;code&gt;self.someProperty&lt;/code&gt;처럼 그 클로저가 해당 인스턴스의 프로퍼티에 접근하거나, &lt;code&gt;self.someMethod()&lt;/code&gt;처럼 해당 인스턴스의 메소드에 접근할 때 발생한다. 두 경우 모두, 이러한 접근으로 그 클로저가 &lt;code&gt;self&lt;/code&gt;를 &amp;ldquo;캡처&amp;quot;할때, 강한 참조 사이클을 생성하게 된다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Memory Safety (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-53-memory-safety-1/</link><pubDate>Sat, 26 Aug 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-53-memory-safety-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="memory-safety"&gt;Memory Safety&lt;/h2&gt;
&lt;p&gt;스위프트는 기본적으로 코드에서 일어나는 안전하지 않은 행동들을 방지한다. 예를 들어, 스위프트는 변수를 사용하기 전에 초기화가 되어있는지 확인하고, 할당 해제된 메모리에는 접근하지 않으며, 배열의 인덱스 값들이 범위 안에 있는지 확인한다.&lt;/p&gt;
&lt;p&gt;또한 스위프트는 메모리를 수정하는 코드가 해당 메모리에 독점적으로 접근하도록 요구하여 같은 위치에 있는 메모리에 대한 동시 접근이 충돌하지 않게 한다. 스위프트가 메모리를 자동적으로 수정하기 때문에, 대부분의 경우에는 메모리 접근에 대해 생각하지 않아도 된다. 하지만, 충돌이 발생할 수 있는 잠재적인 위치를 이해하여, 메모리에 접근할 때 충돌하는 코드 작성을 회피하는 것도 중요하다. 만약 충돌을 일으키는 코드라면, 컴파일 에러 혹은 런타임 에러를 발생시키게 된다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Memory Safety (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-54-memory-safety-2/</link><pubDate>Mon, 27 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-54-memory-safety-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="conflicting-access-to-in-out-parameters"&gt;Conflicting Access to In-Out Parameters&lt;/h2&gt;
&lt;p&gt;함수는 모든 in-out 파라미터에 대한 장기 쓰기 접근 권한을 가지고 있다. in-out 파라미터에 대한 쓰기 권한은 모든 non-in-out 파라미터가 evaluate된 후에 시작되어 함수가 호출되는 전체 기간동안 유지된다. 여러개의 in-out 파라미터가 존재할 경우, 쓰기 접근 파라미터들이 보이는 순서대로 시작된다.&lt;/p&gt;
&lt;p&gt;이 장기 쓰기 접근 권한의 결과중 하나는 스코프 규칙(scoping rule)과 액세스 컨트롤이 허락하더라도, in-out으로 전달된 원본 변수에 접근할 수 없다는 것이다—원본에 접근하는 것은 충돌을 발생시킨다:&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Access Control (1)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-55-access-control-1/</link><pubDate>Tue, 28 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-55-access-control-1/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h1 id="access-control"&gt;Access Control&lt;/h1&gt;
&lt;p&gt;액세스 컨트롤은 다른 소스 파일이나 모듈에서 코드의 일부분에 접근하는 것을 제한한다. 이 기능은 코드의 구체적인 구현 사항을 숨기면서 해당 코드에 접근하고 사용할 선호하는 인터페이스를 지정할 수 있게 해준다.&lt;/p&gt;
&lt;p&gt;개별 타입들 (클래스, 스트럭처, 이뉴머레이션) 뿐만 아니라 해당 타입에 포함된 프로퍼티, 메소드, 이니셜라이저, 서브스크립트에도 접근 레벨을 지정할 수 있다. 프로토콜도 특정 컨텍스트로 제한할 수 있으며, 글로벌 상수, 변수, 함수도 가능하다.&lt;/p&gt;
&lt;p&gt;다양한 레벨의 액세스 컨트롤을 제공하는 것에 더해서, Swift는 일반적인 시나리오에 대해서 기본 액세스 레벨을 제공해서 명시적으로 액세스 컨트롤 레벨을 지정할 필요를 줄였다. 만약 싱글 타겟 앱을 작성하고 있다면, 아마도 명시적인 액세스 컨트롤을 지정할 필요가 없을 것이다.&lt;/p&gt;</description></item><item><title>The Swift Programming Language. Access Control (2)</title><link>https://kelly-chui.github.io/posts/the-swift-programming-language-56-access-control-2/</link><pubDate>Wed, 29 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/the-swift-programming-language-56-access-control-2/</guid><description>&lt;figure class="theme-image"&gt;
&lt;img
class="theme-image__image theme-image__image--light"
src="https://kelly-chui.github.io/images/assets/swift-logo-light.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;img
class="theme-image__image theme-image__image--dark"
src="https://kelly-chui.github.io/images/assets/swift-logo-dark.svg"
alt="Swift logo"
loading="lazy"
decoding="async"
&gt;
&lt;/figure&gt;
&lt;h2 id="custom-types"&gt;Custom Types&lt;/h2&gt;
&lt;p&gt;커스텀 타입에 대한 명시적인 액세스 레벨을 지정하고 싶으면, 타입을 정의할 때 하면 된다. 새로운 타입은 액세스 레벨이 허용하는 곳이라면 어디에서든 사용할 수 있다. 예를 들어, file-private한 클래스를 정의하면, 그 클래스가 정의된 소스 파일 내부에서 프로퍼티나, 함수의 파라미터 혹은 리턴 타입으로만 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;또한 타입의 액세스 컨트롤 레벨은 타입의 &lt;em&gt;멤버&lt;/em&gt;(프로퍼티, 메소드, 이니셜라이저, 서브스크립트)의 기본 액세스 레벨에도 영향을 끼친다. 만약 타입의 액세스 레벨을 private이나 file private으로 정의했다면, 멤버들의 기본 액세스 레벨도 private이나 file private이 된다. 만약 타입의 액세스 레벨을 internal 이나 public으로 정의했다면(혹은 액세스 레벨을 명시적으로 지정하지 않아 기본 액세스 레벨 internal을 사용한다면), 타입의 멤버의 기본 액세스 레벨은 internal이 된다.&lt;/p&gt;</description></item><item><title>TIL. Aug 18, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-18/</link><pubDate>Tue, 18 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-18/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Stack Day
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LocalDay&lt;/code&gt; 날짜 모델 도입&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Clock&lt;/code&gt;과 &lt;code&gt;FixedClock&lt;/code&gt; 추가&lt;/li&gt;
&lt;li&gt;완료 기록·취소·보관·삭제 UseCase를 날짜 모델에 맞게 수정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;InMemoryHabitRepository&lt;/code&gt;, &lt;code&gt;InMemoryCompletionRepository&lt;/code&gt; 구현 및 테스트 추가&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-localday-time-boundary/"&gt;StackDay. Date로 하루를 표현하면 생기는 문제&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="localday-도입하기"&gt;LocalDay 도입하기&lt;/h3&gt;
&lt;p&gt;Stack Day에서는 &lt;code&gt;Date&lt;/code&gt; 하나로 특정 시점과 특정 날짜를 모두 표현하고 있었다. 그래서 달력상의 날짜만 필요한 값을 &lt;code&gt;LocalDay&lt;/code&gt;로 분리했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;LocalDay&lt;/code&gt;: &lt;code&gt;startedOn&lt;/code&gt;, &lt;code&gt;archivedOn&lt;/code&gt;, &lt;code&gt;completedOn&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Date&lt;/code&gt;: &lt;code&gt;createdAt&lt;/code&gt;, &lt;code&gt;updatedAt&lt;/code&gt;, &lt;code&gt;recordedAt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;현재 시각은 &lt;code&gt;Clock&lt;/code&gt;이 제공하고, 그 시각을 어느 날짜로 해석할지는 TimeZone이 결정하도록 분리했다. 전체 설계와 구현 코드는 &lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-localday-time-boundary/"&gt;개발일지&lt;/a&gt;에 정리했다.&lt;/p&gt;</description></item><item><title>StackDay. Date는 날짜가 아니다</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-localday-time-boundary/</link><pubDate>Tue, 18 Aug 2026 17:52:46 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-localday-time-boundary/</guid><description>&lt;p&gt;StackDay는 일정 주기의 습관 수행 여부를 기록하는 앱이고, MVP에서는 그 주기를 매일로 고정했다.&lt;/p&gt;
&lt;p&gt;지금까지 구현할 때, &amp;ldquo;어느 날에 수행했는가&amp;quot;와 &amp;ldquo;정확히 언제 기록했는가&amp;quot;를 모두 Foundation의 &lt;code&gt;Date&lt;/code&gt;로 표현했다.&lt;/p&gt;
&lt;p&gt;두 정보는 비슷해 보이지만 다르다. 이 차이를 타입으로 구분하지 않으면 날짜 검증, 중복 기록 검사, 통계 계산마다 같은 해석을 반복하게 된다.&lt;/p&gt;
&lt;p&gt;이번 글에서는 그 문제가 실제 코드에서 어떻게 드러났고, &lt;code&gt;LocalDay&lt;/code&gt;·&lt;code&gt;Clock&lt;/code&gt;·TimeZone을 어떤 경계로 나눴는지 정리한다.&lt;/p&gt;
&lt;h2 id="date타입이-저장하는-것은-순간"&gt;Date타입이 저장하는 것은 순간&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Date&lt;/code&gt;는 연, 월, 일이나 자정 같은 달력 개념을 저장하지 않는다.&lt;/p&gt;</description></item><item><title>TIL. Aug 17, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-17/</link><pubDate>Mon, 17 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-17/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-1563-stone-game-v/"&gt;LeetCode 1563. Stone Game V&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WWDC
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-2/"&gt;Swift Concurrency. Explore Structured Concurrency in Swift (2) - WWDC21&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;마이그레이션
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/cs-algorithm-kadanes-algorithm/"&gt;Algorithm. Kadane&amp;rsquo;s Algorithm&lt;/a&gt; 마이그레이션&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/mibangmurok-dev-log-colorpicker/"&gt;미방문록. 대표 색상 추출 Picker 만들기&lt;/a&gt; 마이그레이션&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="unstructured-task"&gt;Unstructured Task&lt;/h3&gt;
&lt;p&gt;WWDC21 Explore Structured Concurrency in Swift 세션을 정리를 마무리했다.&lt;/p&gt;
&lt;p&gt;1편과 다르게 구조화된 task tree에 속하지 않는 unstructured task와 detached task를 정리했다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Task { ... }&lt;/code&gt;로 만든 unstructured task는 생성한 scope가 끝나도 계속 실행될 수 있다. 생성 지점의 actor, priority, task-local value를 상속한다.&lt;/p&gt;</description></item><item><title>Swift Concurrency. Explore Structured Concurrency in Swift (2) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-2/</link><pubDate>Mon, 17 Aug 2026 19:50:17 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-2/</guid><description>&lt;p&gt;&lt;a href="https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-1/"&gt;앞선 포스팅&lt;/a&gt;에서는 구조화된 동시성이 task 계층 구조를 활용해 제어 흐름을 일반 동기 코드처럼 만들고, 에러 전파와 cancellation을 단순하게 만드는 방식을 정리했다.&lt;/p&gt;
&lt;p&gt;이 포스팅에서는 계층 구조가 없는 task, 즉 unstructured task(구조화되지 않은 동시성)에 대해 정리한다.&lt;/p&gt;
&lt;h2 id="not-all-tasks-fit-a-structured-pattern"&gt;Not all tasks fit a structured pattern&lt;/h2&gt;
&lt;p&gt;동기 코드에서 처음으로 비동기 연산을 시작하는 경우처럼 parent task가 존재하지 않거나, task의 생명주기가 하나의 스코프에 들어맞지 않는 경우가 있을 수 있다.&lt;/p&gt;
&lt;p&gt;이런 경우는 특히 UIKit에서 delegate를 구현할 때 자주 발생한다.&lt;/p&gt;</description></item><item><title>LeetCode 1563. Stone Game V</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1563-stone-game-v/</link><pubDate>Mon, 17 Aug 2026 11:30:13 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1563-stone-game-v/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-v"&gt;https://leetcode.com/problems/stone-game-v&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;돌이 일렬로 놓여 있고, 매 턴마다 현재 구간을 둘로 나눈 뒤 더 작은 합을 가진 쪽을 가져간다. Alice가 얻을 수 있는 최대 점수를 리턴하는 문제이다.&lt;/p&gt;
&lt;p&gt;매 턴마다 현재 구간을 둘로 나눈 뒤 더 작은 합을 가진 쪽을 가져가므로, 구간 DP로 보는 게 자연스럽다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[left][right]&lt;/code&gt;를 &lt;code&gt;stoneValue[left...right]&lt;/code&gt; 구간에서 Alice가 얻을 수 있는 최대 점수라고 하자. 구간을 &lt;code&gt;split&lt;/code&gt;으로 나눠서 왼쪽 합과 오른쪽 합을 비교하면 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;왼쪽 합이 더 작으면 왼쪽을 가져간다.&lt;/li&gt;
&lt;li&gt;오른쪽 합이 더 작으면 오른쪽을 가져간다.&lt;/li&gt;
&lt;li&gt;두 합이 같으면 둘 중 더 좋은 쪽을 선택한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;구간 합은 Prefix Sum으로 미리 구해두면 되고, &lt;code&gt;dp&lt;/code&gt;는 짧은 구간부터 채우면 된다. 각 구간마다 모든 분할을 확인하므로 전체 시간 복잡도는 $O(n^3)$이다.&lt;/p&gt;</description></item><item><title>TIL. Aug 16, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-16/</link><pubDate>Sun, 16 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-16/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-1360d-buying-shovels/"&gt;Codeforces 1360D. Buying Shovels&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stack Day
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CancelCompletionUseCase&lt;/code&gt;, &lt;code&gt;ArchiveHabitUseCase&lt;/code&gt;, &lt;code&gt;DeleteHabitUseCase&lt;/code&gt; 구현&lt;/li&gt;
&lt;li&gt;완료 기록 삭제 테스트와 공통 테스트 Repository 정리&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-completion-identity/"&gt;StackDay. 완료 기록을 취소할 때 무엇을 삭제해야 할까&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="in-memory-repository와-테스트-용도-repository"&gt;in-memory Repository와 테스트 용도 Repository&lt;/h3&gt;
&lt;p&gt;프로덕션의 In-Memory Repository는 실제 저장 상태를 다루고, 테스트용 Repository는 호출과 오류를 관찰하는 Test Double이다. 같은 형태로 보이더라도 목적이 달라 분리했다.&lt;/p&gt;
&lt;h3 id="id와-business-key"&gt;ID와 Business Key&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Completion.ID&lt;/code&gt;는 기록 자체를 식별하고, &lt;code&gt;(habitID, completedOn)&lt;/code&gt;은 현재 정책에서 해당 날짜의 기록을 찾는 조건으로 분리했다. 없는 기록 취소를 성공으로 넘기지 않은 이유까지 &lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-completion-identity/"&gt;개발일지&lt;/a&gt;에 정리했다.&lt;/p&gt;</description></item><item><title>StackDay. 비즈니스 규칙과 Entity Identity 분리하기</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-completion-identity/</link><pubDate>Sun, 16 Aug 2026 15:23:36 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-completion-identity/</guid><description>&lt;p&gt;현재 StackDay MVP에서는 하나의 &lt;code&gt;Habit&lt;/code&gt;에 대해 하루 한 번만 &lt;code&gt;Completion&lt;/code&gt;을 기록할 수 있다.&lt;/p&gt;
&lt;p&gt;그래서 처음에는 &lt;code&gt;(habitID, completedOn)&lt;/code&gt; 조합을 Completion의 identity처럼 사용해도 될 것 같았고, 실제로 그런 코드도 있었다.&lt;/p&gt;
&lt;p&gt;하지만 &lt;code&gt;Completion&lt;/code&gt; 삭제를 구현하면서 이 둘을 분리해야 한다는 점을 알게 되었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Equatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Identifiable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;habitID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;completedOn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;recordedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="같은-날의-기록을-찾는-조건"&gt;같은 날의 기록을 찾는 조건&lt;/h2&gt;
&lt;p&gt;같은 &lt;code&gt;Habit&lt;/code&gt;의 같은 날 &lt;code&gt;Completion&lt;/code&gt;을 찾는 데에는 &lt;code&gt;habitID&lt;/code&gt;와 &lt;code&gt;completedOn&lt;/code&gt;이 필요하다. 현재 정책에서는 이 조건으로 중복 기록도 막을 수 있다.&lt;/p&gt;
&lt;p&gt;하지만 이것은 현재 정책에서 필요한 조회 조건이다. 이후 시간 단위로 습관을 기록하거나, 하루에 여러 번 수행하는 &lt;code&gt;Habit&lt;/code&gt;이 생기면 같은 조합으로 여러 &lt;code&gt;Completion&lt;/code&gt;이 존재할 수 있다.&lt;/p&gt;</description></item><item><title>Codeforces 1360D. Buying Shovels</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-1360d-buying-shovels/</link><pubDate>Sun, 16 Aug 2026 10:53:55 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-1360d-buying-shovels/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/1360/D"&gt;https://codeforces.com/problemset/problem/1360/D&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정확히 &lt;code&gt;n&lt;/code&gt;개의 삽을 사야 하고, 한 번에 살 수 있는 패키지 크기는 &lt;code&gt;1&lt;/code&gt;부터 &lt;code&gt;k&lt;/code&gt;까지이다. 또한 한 번 고른 패키지 크기만 계속 사야 하므로, 결국 &lt;code&gt;n&lt;/code&gt;을 나누는 어떤 수 &lt;code&gt;x&lt;/code&gt;를 골라 &lt;code&gt;n / x&lt;/code&gt;개의 패키지를 사는 문제로 바뀐다.&lt;/p&gt;
&lt;p&gt;패키지 개수를 최소화하려면 패키지 크기 &lt;code&gt;x&lt;/code&gt;를 최대한 크게 잡아야 한다. 따라서 &lt;code&gt;n&lt;/code&gt;의 약수 중에서 &lt;code&gt;k&lt;/code&gt; 이하인 가장 큰 값을 찾으면 된다.&lt;/p&gt;
&lt;p&gt;예를 들어 &lt;code&gt;n = 8&lt;/code&gt;, &lt;code&gt;k = 7&lt;/code&gt;이면 &lt;code&gt;8&lt;/code&gt;의 약수는 &lt;code&gt;1, 2, 4, 8&lt;/code&gt;인데, 이 중 &lt;code&gt;k&lt;/code&gt; 이하인 가장 큰 약수는 &lt;code&gt;4&lt;/code&gt;이다. 그래서 답은 &lt;code&gt;8 / 4 = 2&lt;/code&gt;가 된다.&lt;/p&gt;</description></item><item><title>LeetCode 2029. Stone Game IX</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-2029-stone-game-ix/</link><pubDate>Sun, 16 Aug 2026 10:22:55 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-2029-stone-game-ix/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-ix"&gt;https://leetcode.com/problems/stone-game-ix&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;돌을 순서대로 가져가면서, 합이 &lt;code&gt;3&lt;/code&gt;의 배수가 되지 않게 해야 하는 게임이다. Alice가 이길 수 있는지 리턴하는 문제이다.&lt;/p&gt;
&lt;p&gt;각 돌의 값은 &lt;code&gt;3&lt;/code&gt;으로 나눈 나머지만 보면 된다. 합이 &lt;code&gt;3&lt;/code&gt;의 배수인지 아닌지만 중요하기 때문이다. 그래서 &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;의 개수만 세면 충분하다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;0&lt;/code&gt;은 합의 나머지를 바꾸지 않으므로, 실제 승부는 &lt;code&gt;1&lt;/code&gt;과 &lt;code&gt;2&lt;/code&gt;를 어떻게 번갈아 쓰느냐에 달려 있다. &lt;code&gt;count[0]&lt;/code&gt;이 짝수인지 홀수인지에 따라 가능한 진행이 달라진다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;count[0]&lt;/code&gt;이 짝수면 &lt;code&gt;1&lt;/code&gt;과 &lt;code&gt;2&lt;/code&gt;가 둘 다 있어야 한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;count[0]&lt;/code&gt;이 홀수면 &lt;code&gt;1&lt;/code&gt;과 &lt;code&gt;2&lt;/code&gt;의 개수 차이가 너무 크면 안 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;stoneGameIX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;stones&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;stone&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stones&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;stone&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;count0&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;count1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;count2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count0&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;count2&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;count2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>TIL. Aug 15, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-15/</link><pubDate>Sat, 15 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-15/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-276c-little-girl-and-maximum-sum/"&gt;Codeforces 276C. Little Girl and Maximum Sum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3702-longest-subsequence-with-non-zero-bitwise-xor/"&gt;LeetCode 3702. Longest Subsequence With Non-Zero Bitwise XOR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-1/"&gt;Swift Concurrency. Explore Structured Concurrency in Swift (1) - WWDC21&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="structured-concurrency"&gt;Structured Concurrency&lt;/h3&gt;
&lt;p&gt;Explore Structured Concurrency in Swift WWDC 세션을 봤다.&lt;/p&gt;
&lt;p&gt;Meet async/await in Swift 세션도 마찬가지고, 이번 세션을 보면서 느낀 것은 Swift Concurrency의 중요한 컨셉은 비동기 코드를 일반적인 동기 코드와 비슷한 흐름으로 작성할 수 있게 하는 것이라고 생각했다.&lt;/p&gt;
&lt;p&gt;async/await가 에러 핸들링과 같은 부분을 비동기 코드도 동기 코드와 비슷하게 사용할 수 있게 해줬다면, Structured Concurrency는 조건문이나 루프같은 제어 흐름도 동기 코드와 비슷하게 사용하게 해준다.&lt;/p&gt;</description></item><item><title>Swift Concurrency. Explore Structured Concurrency in Swift (1) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-1/</link><pubDate>Sat, 15 Aug 2026 15:54:01 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-explore-structured-concurrency-in-swift-1/</guid><description>&lt;p&gt;&lt;a href="https://kelly-chui.github.io/posts/wwdc-swift-concurrency-meet-async-await-in-swift-1/"&gt;앞서 정리한 세션&lt;/a&gt;에서는 completion handler 기반의 비동기 코드를 async/await로 작성하면서, 비동기 코드에서도 return, throw, try-catch와 같은 일반적인 제어 흐름을 사용할 수 있게 되었다.&lt;/p&gt;
&lt;p&gt;이번 포스팅에서는 WWDC21의 Explore Structured Concurrency in Swift 세션을 정리한다. async/await가 비동기 코드의 제어 흐름을 구조화했다면, structured concurrency는 여기서 더 나아가 동시에 실행되는 여러 task의 관계와 수명을 구조화한다.&lt;/p&gt;
&lt;h2 id="explore-structed-concurrency-in-swift"&gt;Explore Structed Concurrency in Swift&lt;/h2&gt;
&lt;p&gt;Swift Concurrency는 구조화된 프로그래밍(structured programming)의 아이디어에 기반한 structured concurrency라는 개념을 활용한다.&lt;/p&gt;
&lt;p&gt;옛날에는 프로그램에서 명령어를 나열하고, 컨트롤 플로우가 여기저기로 자유롭게 점프해서 코드를 읽기가 매우 어려웠다. (C의 &lt;code&gt;goto&lt;/code&gt;를 생각해보자)&lt;/p&gt;</description></item><item><title>Codeforces 276C. Little Girl and Maximum Sum</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-276c-little-girl-and-maximum-sum/</link><pubDate>Sat, 15 Aug 2026 12:48:53 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-276c-little-girl-and-maximum-sum/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/276/C"&gt;https://codeforces.com/problemset/problem/276/C&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;크기 &lt;code&gt;n&lt;/code&gt;인 수열 &lt;code&gt;a&lt;/code&gt;와 쿼리 &lt;code&gt;q&lt;/code&gt;개가 주어진다. 각 쿼리는 인덱스 $[l, r]$ 범위를 지정하며, 해당 범위의 원소 합을 구한다. 수열 &lt;code&gt;a&lt;/code&gt;를 적절히 재배열하여 모든 쿼리의 합의 총합을 최대화 한 수를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;쿼리가 여러번 나오고 어떤 원소들은 쿼리 안에 중복되어서 포함되어 있을 수 있다. 쿼리의 범위 안에 가장 많이 포함된 원소의 순서대로, 높은 값을 배치하는 정렬 문제로 환원된다.&lt;/p&gt;
&lt;p&gt;어떤 원소 $a_i$가 쿼리 내부에 포함되어 있는지를 일반적으로 판단하게 되면 $O(q \times n)$이 되는데, &lt;code&gt;q&lt;/code&gt;, &lt;code&gt;n&lt;/code&gt;의 범위가 $1 \leq q 2 \times 10^5$ 이므로, 시간 안에 문제를 해결하기 어려워진다.&lt;/p&gt;</description></item><item><title>Leetcode 3702. Longest Subsequence With Non-Zero Bitwise XOR</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3702-longest-subsequence-with-non-zero-bitwise-xor/</link><pubDate>Sat, 15 Aug 2026 12:38:30 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3702-longest-subsequence-with-non-zero-bitwise-xor/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/longest-subsequence-with-non-zero-bitwise-xor"&gt;https://leetcode.com/problems/longest-subsequence-with-non-zero-bitwise-xor&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;수열 &lt;code&gt;nums&lt;/code&gt;가 주어지고, 이 &lt;code&gt;nums&lt;/code&gt;의 서브시퀀스 중, 모든 원소를 XOR해서 0이 아니게 되는 서브시퀀스의 최대 길이를 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;이 문제는 XOR 연산의 특성을 잘 알아야 한다. 만약 XOR이 아니라 $+$이었다면, 모든 $\text{nums}$의 원소들을 더해보고, 0이 아니라면 $\text{nums}$ 전체를, 0이라면 원소 중 0이 아닌 것 하나를 제외하면 된다. $+$의 역연산은 $-$이므로, 어떤 원소 $x$를 제외했을 때 다음과 같이 된다.&lt;/p&gt;
&lt;p&gt;$$\sum \text{nums} - x \neq 0$$&lt;/p&gt;
&lt;p&gt;만약 모든 원소가 0이라면 답은 0이 된다.&lt;/p&gt;</description></item><item><title>TIL. Aug 14, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-14/</link><pubDate>Fri, 14 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-14/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-550a-two-substrings/"&gt;Codeforces 550A. Two Substrings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3090-maximum-length-substring-with-two-occurrences/"&gt;LeetCode 3090. Maximum Length Substring With Two Occurrences&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stack Day
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HabitRepository&lt;/code&gt;, &lt;code&gt;CompletionRepository&lt;/code&gt; 인터페이스 추가&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CreateHabitUseCase&lt;/code&gt;와 &lt;code&gt;RecordCompletionUseCase&lt;/code&gt; 구현&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-usecase-entity-responsibilities/"&gt;StackDay. UseCase와 Entity는 각각 어디까지 책임져야 할까&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-repository-contracts/"&gt;StackDay. Repository의 save를 insert와 update로 나눈 이유&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="usecase와-entity의-책임"&gt;UseCase와 Entity의 책임&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;CreateHabitUseCase&lt;/code&gt;와 &lt;code&gt;RecordCompletionUseCase&lt;/code&gt;를 구현하면서, Entity가 스스로 유효한 상태를 보장하고 UseCase는 객체를 조합해 작업 흐름을 만드는 쪽으로 책임을 나눴다.&lt;/p&gt;
&lt;p&gt;이름 정규화와 유효성 검증은 &lt;code&gt;Habit&lt;/code&gt;에, 저장 순서와 중복 확인은 UseCase에 뒀다. 자세한 고민은 &lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-usecase-entity-responsibilities/"&gt;개발일지&lt;/a&gt;에 정리했다.&lt;/p&gt;</description></item><item><title>StackDay. UseCase와 Entity는 각각 어디까지 책임져야 할까</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-usecase-entity-responsibilities/</link><pubDate>Fri, 14 Aug 2026 16:31:52 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-usecase-entity-responsibilities/</guid><description>&lt;p&gt;&lt;code&gt;CreateHabitUseCase&lt;/code&gt;를 시작으로 여러 유즈케이스를 구현하면서, 도메인 규칙을 어디에 두어야 할지 계속 고민하게 됐다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Habit&lt;/code&gt;을 생성할 때 이름의 유효성을 누가 검증해야 하는지, &lt;code&gt;Completion&lt;/code&gt;을 남길 때 해당 날짜에 기록할 수 있는지는 누가 판단해야 하는지처럼 비슷한 문제가 반복해서 나타났다.&lt;/p&gt;
&lt;p&gt;처음에는 유즈케이스가 사용자의 작업을 처리하니 이런 검증도 함께 담당하면 된다고 생각할 수 있었다. 하지만 구현을 진행할수록 엔티티가 스스로 보장해야 하는 규칙과 유즈케이스 작업의 흐름을 위해 판단해야 하는 규칙을 구분할 필요가 있었다.&lt;/p&gt;
&lt;p&gt;이 포스트에서는 &lt;code&gt;Habit&lt;/code&gt;의 생성과 &lt;code&gt;Completion&lt;/code&gt; 기록을 중심으로 어떤 고민을 했는지와 어떻게 해결했는지를 정리한다.&lt;/p&gt;</description></item><item><title>StackDay. Repository의 save를 insert와 update로 나누기</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-repository-contracts/</link><pubDate>Fri, 14 Aug 2026 14:15:52 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-repository-contracts/</guid><description>&lt;p&gt;유즈케이스를 구현하면서 &lt;code&gt;Habit&lt;/code&gt;과 &lt;code&gt;Completion&lt;/code&gt;을 저장할 Repository 계약을 좀 정리했다.&lt;/p&gt;
&lt;p&gt;처음에는 create와 update 둘 다 &lt;code&gt;save&lt;/code&gt; 하나로 저장하면 간단해 보였지만, 두 기능이 기대하는 실패 조건이 서로 다르다는 점에서 계약을 나눌 필요가 있었다.&lt;/p&gt;
&lt;h2 id="save는-어떤-동작인가"&gt;save는 어떤 동작인가&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;save&lt;/code&gt;를 upsert로 구현하면 호출하는 쪽은 편하다. ID가 없으면 삽입하고, 이미 있으면 갱신하면 된다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;HabitRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;habit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Habit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;문제는 이 동작이 실패해야 하는 상황까지 조용히 성공으로 바꾼다는 점이다.&lt;/p&gt;
&lt;p&gt;(물론 UUID라 현실적으로 겹칠 일은 없지만) &lt;code&gt;Habit&lt;/code&gt;을 생성하는 작업은 같은 ID가 이미 있으면 실패해야 하고, 보관처럼 기존 &lt;code&gt;Habit&lt;/code&gt;을 바꾸는 작업은 대상이 없으면 실패해야 한다.&lt;/p&gt;</description></item><item><title>Codeforces 550A. Two Substrings</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-550a-two-substrings/</link><pubDate>Fri, 14 Aug 2026 12:17:14 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-550a-two-substrings/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/550/A"&gt;https://codeforces.com/problemset/problem/550/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;스트링 &lt;code&gt;s&lt;/code&gt;가 주어지고, 이 &lt;code&gt;s&lt;/code&gt; 안에서 서브스트링 &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;와 &lt;code&gt;&amp;quot;BA&amp;quot;&lt;/code&gt;가 겹쳐지지 않은 상태로 존재하면 &lt;code&gt;&amp;quot;YES&amp;quot;&lt;/code&gt; 아니라면 &lt;code&gt;&amp;quot;NO&amp;quot;&lt;/code&gt; 출력하면 된다.&lt;/p&gt;
&lt;p&gt;문제에서 주어진 예시인 &lt;code&gt;&amp;quot;ABA&amp;quot;&lt;/code&gt; 같은 경우는 &lt;code&gt;&amp;quot;NO&amp;quot;&lt;/code&gt;가 된다. &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;와 &lt;code&gt;&amp;quot;BA&amp;quot;&lt;/code&gt;가 서로 따로 존재하지 않기 때문이다. 하지만 &lt;code&gt;&amp;quot;ABCABA&amp;quot;&lt;/code&gt; 같은 경우에는 &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;와 &lt;code&gt;&amp;quot;BA&amp;quot;&lt;/code&gt;가 &lt;code&gt;&amp;quot;BA&amp;quot;&lt;/code&gt;는 겹쳐져 있지만 이미 앞에서 &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;가 존재하기 때문에, &lt;code&gt;&amp;quot;YES&amp;quot;&lt;/code&gt;가 된다.&lt;/p&gt;
&lt;p&gt;이런 예외들을 알아내면, 문제를 푸는 방식은 단순하다. &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;를 찾은 후, 그 이후(&lt;code&gt;&amp;quot;B&amp;quot;&lt;/code&gt; 이후)에 있는 인덱스부터 &lt;code&gt;&amp;quot;BA&amp;quot;&lt;/code&gt;를 찾고, 만약 존재한다면 &lt;code&gt;&amp;quot;YES&amp;quot;&lt;/code&gt;, 존재하지 않는다면 다시 &lt;code&gt;&amp;quot;BA&amp;quot;&lt;/code&gt;를 먼저 찾은 후, &lt;code&gt;&amp;quot;A&amp;quot;&lt;/code&gt;의 인덱스 이후에 있는 인덱스부터 &lt;code&gt;&amp;quot;AB&amp;quot;&lt;/code&gt;를 찾으면 된다. 둘 다 불가능하다면 &lt;code&gt;&amp;quot;NO&amp;quot;&lt;/code&gt;가 된다.&lt;/p&gt;</description></item><item><title>Leetcode 3090. Maximum Length Substring With Two Occurrences</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3090-maximum-length-substring-with-two-occurrences/</link><pubDate>Fri, 14 Aug 2026 11:53:07 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3090-maximum-length-substring-with-two-occurrences/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/maximum-length-substring-with-two-occurrences"&gt;https://leetcode.com/problems/maximum-length-substring-with-two-occurrences&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;스트링 &lt;code&gt;s&lt;/code&gt;가 주어지고, 스트링 &lt;code&gt;s&lt;/code&gt;의 서브스트링 중에서 같은 문자가 최대 2번 까지만 등장하는 서브스트링의 최대 길이를 리턴하는 문제이다.&lt;/p&gt;
&lt;p&gt;투 포인터를 이용해서, 서브스트링 내부의 각 문자의 개수는 &lt;code&gt;frequencies&lt;/code&gt; 딕셔너리로 추적하고, 같은 문자가 2개를 초과하면 &lt;code&gt;start&lt;/code&gt;, 그렇지 않다면 &lt;code&gt;end&lt;/code&gt;를 증가시키는 방향으로 &lt;code&gt;s&lt;/code&gt;를 탐색하면 된다.&lt;/p&gt;
&lt;p&gt;문제의 제약조건이 널널해서 $O(n^2)$ 방식의 브루트 포스로도 풀 수 있지만 투 포인터를 이용하면 $O(n)$으로 쉽게 풀 수 있다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;maximumLengthSubstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>TIL. Aug 13, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-13/</link><pubDate>Thu, 13 Aug 2026 21:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-13/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/cs-data-structure-segment-tree/"&gt;Data Structure. Segment Tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-2213-longest-substring-of-one-repeating-character/"&gt;LeetCode 2213. Longest Substring of One Repeating Character&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-separating-responsibility-and-types/"&gt;StackDay. 책임 분리와 타입 분리&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="stackday-통계-계산"&gt;StackDay 통계 계산&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;HabitStatistics&lt;/code&gt;를 구현하면서 계산 결과를 표현하는 타입과 계산 로직을 분리했다. 다만 &lt;code&gt;HabitStatisticsCalculator&lt;/code&gt;가 &lt;code&gt;HabitStreakCalculator&lt;/code&gt;에 의존하게 되면서, 여러 Calculator가 같은 날짜 정규화와 완료 기록 필터링을 반복하는 문제가 보였다.&lt;/p&gt;
&lt;p&gt;타입을 나누는 것만으로 항상 구조가 좋아지는 것은 아니고, 공유하는 계산 맥락까지 함께 살펴봐야 한다는 점을 배웠다. 자세한 고민은 &lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-separating-responsibility-and-types/"&gt;StackDay 개발일지&lt;/a&gt;에 정리했다.&lt;/p&gt;</description></item><item><title>Leetcode 2213. Longest Substring of One Repeating Character</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-2213-longest-substring-of-one-repeating-character/</link><pubDate>Thu, 13 Aug 2026 20:45:10 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-2213-longest-substring-of-one-repeating-character/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/longest-substring-of-one-repeating-character"&gt;https://leetcode.com/problems/longest-substring-of-one-repeating-character&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;스트링 &lt;code&gt;s&lt;/code&gt;에 대해 여러 번의 문자 변경 쿼리가 주어진다. 각 쿼리마다 특정 인덱스의 문자를 변경하고, 같은 문자가 연속되는 가장 긴 부분 스트링의 길이를 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;스트링의 길이와 쿼리의 개수가 최대 $10^5$이므로, 문자를 변경할 때마다 스트링 전체를 탐색하는 방식으로는 해결할 수 없다.&lt;/p&gt;
&lt;p&gt;문자 하나를 변경하는 업데이트가 반복되고, 변경 이후 스트링 전체에서 가장 긴 연속 스트링의 길이를 구해야 한다. 따라서 변경된 구간만 갱신할 수 있는 &lt;a href="https://kelly-chui.github.io/posts/cs-data-structure-segment-tree/"&gt;Segment Tree&lt;/a&gt;를 사용했다.&lt;/p&gt;
&lt;p&gt;다만, 단순히 concat을 하면 안되고, 두 접합부의 경계를 확인한 다음 처리를 해줘야 한다.&lt;/p&gt;</description></item><item><title>StackDay. 책임 분리와 타입 분리</title><link>https://kelly-chui.github.io/posts/stackday-dev-log-separating-responsibility-and-types/</link><pubDate>Thu, 13 Aug 2026 18:32:51 +0900</pubDate><guid>https://kelly-chui.github.io/posts/stackday-dev-log-separating-responsibility-and-types/</guid><description>&lt;p&gt;이전 작업에서 &lt;code&gt;HabitStreak&lt;/code&gt;을 구현하면서 계산 결과와 계산 로직을 분리했다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HabitStreak&lt;/code&gt;은 현재 스트릭과 최장 스트릭이라는 값만 표현하고, 계산은 &lt;code&gt;HabitStreakCalculator&lt;/code&gt;가 담당한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HabitStreak&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HabitStreakCalculator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;habit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Habit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Completion&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;referenceDate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Calendar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HabitStreak&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;같은 원리로 &lt;code&gt;HabitStatistics&lt;/code&gt;도 파생 값과 계산 책임을 분리해서 구현했다.&lt;/p&gt;
&lt;h2 id="habitstatistics"&gt;HabitStatistics&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;HabitStatistics&lt;/code&gt;는 Habit의 수행 기록을 요약한 파생 값이다.&lt;/p&gt;
&lt;p&gt;MVP에서는 다음 값을 제공한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;HabitStatistics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;totalCompletedDays&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;eligibleTrackingDays&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;completionRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Double&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;streak&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HabitStreak&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;totalCompletedDays&lt;/code&gt;는 추적 기간 안에서 완료한 날짜의 수이고, &lt;code&gt;eligibleTrackingDays&lt;/code&gt;는 시작일부터 기준일까지 추적 대상이 된 날짜의 수다. 아카이브된 Habit은 &lt;code&gt;archivedOn&lt;/code&gt;을 마지막 추적일로 사용한다.&lt;/p&gt;</description></item><item><title>Data Structure. Segment Tree</title><link>https://kelly-chui.github.io/posts/cs-data-structure-segment-tree/</link><pubDate>Thu, 13 Aug 2026 14:18:26 +0900</pubDate><guid>https://kelly-chui.github.io/posts/cs-data-structure-segment-tree/</guid><description>&lt;h2 id="segment-tree"&gt;Segment Tree&lt;/h2&gt;
&lt;p&gt;배열의 특정 구간에 대한 연산을 빠르게 처리하기 위한 이진 트리 형태의 자료구조.&lt;/p&gt;
&lt;p&gt;구간 합, 최솟값, 최댓값처럼 배열의 일정 범위를 대상으로 반복해서 연산해야 하는 경우에 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;일반적인 배열에서 특정 구간의 합을 구하려면 해당 구간의 원소를 직접 순회해야 하므로 $O(n)$의 시간이 필요하다. 세그먼트 트리는 배열의 여러 구간에 대한 연산 결과를 트리 형태로 저장하여 구간 조회를 $O(\log n)$에 처리할 수 있도록 한다.&lt;/p&gt;
&lt;p&gt;특히 배열의 값이 변경되는 상황에서도 구간에 대한 연산을 반복해서 수행해야 할 때 사용할 수 있다.&lt;/p&gt;</description></item><item><title>TIL. Aug 12, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-12/</link><pubDate>Wed, 12 Aug 2026 23:30:00 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-12/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-2958-length-of-longest-subarray-with-at-most-k-frequency/"&gt;LeetCode 2958. Length of Longest Subarray With at Most K Frequency&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-2996-smallest-missing-integer-greater-than-sequential-prepix-sum/"&gt;LeetCode 2996. Smallest Missing Integer Greater Than Sequential Prefix Sum&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/stackday-dev-log-derived-value-responsibility/"&gt;StackDay. 엔티티와 계산 책임 분리하기&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="파생-값을-구현할-때의-책임-분리"&gt;파생 값을 구현할 때의 책임 분리&lt;/h3&gt;
&lt;p&gt;StackDay의 &lt;code&gt;HabitEntry&lt;/code&gt;와 &lt;code&gt;HabitStreak&lt;/code&gt;을 구현했다. 모델링 단계에서 정의한 파생 값을 실제 코드로 옮기면서, 값을 표현하는 타입과 값을 계산하는 로직을 분리했다.&lt;/p&gt;
&lt;p&gt;AI 에이전트가 작성한 내용중에 별로인 것들을 몇개 직접 수정했는데 리스트로 정리하면 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HabitEntry&lt;/code&gt;의 이니셜라이저 전체 &lt;code&gt;Completion&lt;/code&gt; 목록을 직접 탐색하고, 생성 실패/성공을 판정했다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HabitStreak&lt;/code&gt;의 이니셜라이저 내부에 &lt;code&gt;Streak&lt;/code&gt; 계산 로직이 들어있었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;둘 다 경계가 제대로 구분되지 않았다. &lt;code&gt;HabitEntry&lt;/code&gt; 내부에서 전체 &lt;code&gt;Completion&lt;/code&gt;을 탐색하면서 조건에 맞는 &lt;code&gt;Completion&lt;/code&gt;을 찾아내는건 비효율적이기도 하고, 이건 유즈케이스에서 해야 될 일이다.&lt;/p&gt;</description></item><item><title>LeetCode 2996. Smallest Missing Integer Greater Than Sequential Prefix Sum</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-2996-smallest-missing-integer-greater-than-sequential-prepix-sum/</link><pubDate>Wed, 12 Aug 2026 22:47:12 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-2996-smallest-missing-integer-greater-than-sequential-prepix-sum/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/smallest-missing-integer-greater-than-sequential-prefix-sum"&gt;https://leetcode.com/problems/smallest-missing-integer-greater-than-sequential-prefix-sum&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정수 배열 &lt;code&gt;nums&lt;/code&gt;가 주어진다. 배열의 첫 원소부터 연속해서 증가하는 부분의 합을 구한 뒤, 그 합보다 크거나 같으면서 배열에 존재하지 않는 가장 작은 정수를 찾으면 된다.&lt;/p&gt;
&lt;p&gt;먼저 첫 번째 원소를 합에 더해두고, 현재 원소가 다음 조건을 만족하는지 확인한다.&lt;/p&gt;
&lt;p&gt;$$
nums[i] = nums[i - 1] + 1
$$&lt;/p&gt;
&lt;p&gt;조건을 만족하는 동안에는 현재 원소를 합에 더하고, 연속 조건이 깨지면 순회를 종료한다.&lt;/p&gt;
&lt;p&gt;이제 구한 합을 후보값으로 두고, 후보값이 배열 안에 있으면 1씩 증가시킨다. 배열에 없는 첫 번째 값이 정답이다. 이 부분은 코드처럼 배열에 후보값이 존재하는 동안 반복하면 된다.&lt;/p&gt;</description></item><item><title>LeetCode 2958. Length of Longest Subarray With at Most K Frequency</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-2958-length-of-longest-subarray-with-at-most-k-frequency/</link><pubDate>Wed, 12 Aug 2026 21:14:37 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-2958-length-of-longest-subarray-with-at-most-k-frequency/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/length-of-longest-subarray-with-at-most-k-frequency"&gt;https://leetcode.com/problems/length-of-longest-subarray-with-at-most-k-frequency&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정수 배열 &lt;code&gt;nums&lt;/code&gt;와 정수 &lt;code&gt;k&lt;/code&gt;가 주어질 때, 어떤 숫자도 &lt;code&gt;k&lt;/code&gt;번보다 많이 등장하지 않는 가장 긴 연속 부분 배열의 길이를 구하면 된다.&lt;/p&gt;
&lt;p&gt;연속 부분 배열이므로 슬라이딩 윈도우를 사용했다. &lt;code&gt;start&lt;/code&gt;부터 &lt;code&gt;end&lt;/code&gt;까지를 현재 윈도우로 두고, &lt;code&gt;end&lt;/code&gt;를 오른쪽으로 이동하면서 숫자별 등장 횟수를 갱신한다.&lt;/p&gt;
&lt;p&gt;새로 추가한 숫자의 등장 횟수가 &lt;code&gt;k&lt;/code&gt;를 초과하면 조건을 만족할 때까지 &lt;code&gt;start&lt;/code&gt;를 오른쪽으로 이동한다. 이때 윈도우의 가장 왼쪽 숫자부터 하나씩 제거하면 된다. 윈도우가 조건을 만족하는 상태가 되면 현재 길이로 정답을 갱신한다.&lt;/p&gt;</description></item><item><title>TIL. Aug 10, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-10/</link><pubDate>Mon, 10 Aug 2026 23:42:07 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-10/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;devbox-light-server
&lt;ul&gt;
&lt;li&gt;Docker 이미지 작성 및 컨테이너 실행&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.data&lt;/code&gt; 볼륨 연결과 healthcheck 추가&lt;/li&gt;
&lt;li&gt;GitHub Actions에서 테스트 이후 이미지를 빌드하도록 구성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;main&lt;/code&gt; 브랜치에 push하면 GHCR에 Docker 이미지를 자동으로 배포하도록 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-1510-stone-game-iv/"&gt;LeetCode 1510&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-1140-stone-game-ii/"&gt;LeetCode 1140&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="stone-game의-승패-dp"&gt;Stone Game의 승패 DP&lt;/h3&gt;
&lt;h4 id="leetcode-1510"&gt;LeetCode 1510&lt;/h4&gt;
&lt;p&gt;Stone Game 시리즈는 현재 플레이어가 이길 수 있는지를 상태로 두고 풀면 된다. Alice가 먼저 시작하는 것은 고정되어 있으므로, Alice와 Bob을 따로 나누기보다 현재 차례의 플레이어 기준으로 생각하는 편이 자연스럽다.&lt;/p&gt;</description></item><item><title>LeetCode 1140. Stone Game II</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1140-stone-game-ii/</link><pubDate>Mon, 10 Aug 2026 22:18:06 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1140-stone-game-ii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-ii"&gt;https://leetcode.com/problems/stone-game-ii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;돌이 일렬로 놓여 있고, 현재 &lt;code&gt;M&lt;/code&gt;일 때 &lt;code&gt;1&lt;/code&gt;개부터 &lt;code&gt;2M&lt;/code&gt;개까지 가져갈 수 있다. 돌을 가져간 뒤에는 &lt;code&gt;M&lt;/code&gt;이 &lt;code&gt;max(M, 가져간 개수)&lt;/code&gt;로 바뀐다. Alice가 항상 먼저 시작하고, Alice가 얻을 수 있는 돌의 최대 개수를 구하면 된다.&lt;/p&gt;
&lt;p&gt;현재 차례인 사람이 상대보다 얼마나 더 많이 가져갈 수 있는지로 DP를 정의할 수도 있지만, 이 문제에서는 현재 상태에서 현재 플레이어가 최대로 가져갈 수 있는 돌의 수를 저장하는 방식이 더 직관적이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i][m]&lt;/code&gt;을 &lt;code&gt;i&lt;/code&gt;번째 돌부터 시작하고 현재 &lt;code&gt;M&lt;/code&gt;이 &lt;code&gt;m&lt;/code&gt;일 때, 현재 플레이어가 얻을 수 있는 최대 돌의 수라고 하자. &lt;code&gt;suffix[i]&lt;/code&gt;는 &lt;code&gt;i&lt;/code&gt;번째 돌부터 끝까지 남은 돌의 합이다.&lt;/p&gt;</description></item><item><title>LeetCode 1510. Stone Game IV</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1510-stone-game-iv/</link><pubDate>Mon, 10 Aug 2026 20:32:58 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1510-stone-game-iv/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-iv"&gt;https://leetcode.com/problems/stone-game-iv&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;돌이 &lt;code&gt;n&lt;/code&gt;개 있고, 매 턴마다 제곱수만큼의 돌을 가져간다. 마지막 돌을 가져가는 사람이 이긴다고 할 때, Alice가 이길 수 있는지 구하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i]&lt;/code&gt;를 돌이 &lt;code&gt;i&lt;/code&gt;개 남았을 때 현재 차례인 사람이 이길 수 있는지로 정의한다. 어떤 제곱수 $r^2$을 가져간 뒤 상대 차례의 상태가 패배라면, 현재 플레이어는 그 선택으로 이길 수 있다.&lt;/p&gt;
&lt;p&gt;따라서 점화식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$
dp[i] = \text{true} \quad \text{if there exists } r \text{ such that } dp[i - r^2] = \text{false}
$$&lt;/p&gt;</description></item><item><title>DevOps. AI 코딩 에이전트 구조적으로 설계하기</title><link>https://kelly-chui.github.io/posts/devops-ai-coding-agent-configuration/</link><pubDate>Mon, 10 Aug 2026 13:15:39 +0900</pubDate><guid>https://kelly-chui.github.io/posts/devops-ai-coding-agent-configuration/</guid><description>&lt;h2 id="ai-에이전트에게-프로젝트를-설명하기"&gt;AI 에이전트에게 프로젝트를 설명하기&lt;/h2&gt;
&lt;p&gt;예전에는 LLM을 이용해 코드를 작성하려면 필요한 기능을 설명하고, 프로젝트의 구조나 현재 상황을 프롬프트로 설명해야 했다. 즉, 프로젝트와 LLM의 API가 사람이었다&amp;hellip;&lt;/p&gt;
&lt;pre class="mermaid" data-mermaid-source="flowchart&amp;#43;LR%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;B%5B%22%ED%94%84%EB%A1%AC%ED%94%84%ED%8A%B8&amp;#43;%EC%9E%91%EC%84%B1%22%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;B&amp;#43;--&amp;#43;%EC%82%AC%EB%9E%8C&amp;#43;--%3E&amp;#43;C%5B%22LLM%EC%9D%B4&amp;#43;%EC%BD%94%EB%93%9C&amp;#43;%EC%83%9D%EC%84%B1%22%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;C&amp;#43;--&amp;#43;%EC%82%AC%EB%9E%8C&amp;#43;--%3E&amp;#43;D%5B%22%28copy&amp;#43;%26&amp;#43;paste&amp;#43;%ED%95%B4%EC%84%9C%29%5Cn%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90&amp;#43;%EC%A0%81%EC%9A%A9%22%5D"&gt;&lt;/pre&gt;&lt;p&gt;반면 Codex나 Claude Code 같은 코딩 에이전트는 프로젝트의 파일을 직접 탐색하고 기존 코드를 분석하면서 작업에 필요한 컨텍스트를 스스로 수집한다.&lt;/p&gt;
&lt;p&gt;하지만 코드만으로 프로젝트의 모든 것을 알 수 있는 것은 아니다. 프로젝트의 규모가 작거나 코드에 충분한 단서가 없다면 의도를 추론하기 어렵고, 반대로 규모가 커질수록 필요한 정보를 찾기 위해 더 많은 코드를 탐색하고 컨텍스트로 사용해야 한다.&lt;/p&gt;</description></item><item><title>TIL. Aug 9, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-09/</link><pubDate>Sun, 09 Aug 2026 22:16:51 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-09/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;dev-data-server-light
&lt;ul&gt;
&lt;li&gt;DB, Auth Token, Storage에 JSON 기반 영속성 추가&lt;/li&gt;
&lt;li&gt;JSON 파일 읽기·쓰기 로직 공통화&lt;/li&gt;
&lt;li&gt;실행 환경에 따라 JSON과 in-memory 저장소를 선택하도록 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stack Day
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Habit&lt;/code&gt;, &lt;code&gt;Habit Entry&lt;/code&gt;, &lt;code&gt;Completion&lt;/code&gt;의 역할을 나눠 데이터 모델링&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="저장-방식은-애플리케이션의-관심사가-아니다"&gt;저장 방식은 애플리케이션의 관심사가 아니다&lt;/h3&gt;
&lt;p&gt;dev-data-server-light를 처음 만들 때는 in-memory 저장소만 사용했다. 개발 중에는 빠르고 편하지만 서버를 재시작하면 유저, 토큰, 파일 데이터가 모두 사라진다. MVP를 마무리하려면 실제로 재시작해도 데이터가 남는 저장 방식이 필요했다.&lt;/p&gt;</description></item><item><title>DevOps. 로컬 LLM을 VSCode와 Xcode에서 코딩 에이전트로 사용하기</title><link>https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-2/</link><pubDate>Sun, 09 Aug 2026 11:08:32 +0900</pubDate><guid>https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-2/</guid><description>&lt;p&gt;&lt;a href="https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-1/"&gt;로컬 LLM 모델을 설치하고&lt;/a&gt; 이어서 로컬 LLM 모델을 Xcode와 VSCode에 연동해보자.&lt;/p&gt;
&lt;p&gt;우선 VSCode에 연결해보고 다음엔 Xcode의 &amp;lsquo;Chat&amp;rsquo; 기능, 최종적으론 OpenCode와 Xcode를 ACP로 연동해서 로컬 LLM을 코딩 에이전트로 이용하려 한다.&lt;/p&gt;
&lt;h2 id="vscode-연결"&gt;VSCode 연결&lt;/h2&gt;
&lt;h3 id="ollama-익스텐션-설치-및-모델-연동"&gt;Ollama 익스텐션 설치 및 모델 연동&lt;/h3&gt;
&lt;p&gt;Ollama에서 공식적으로 VSCode 익스텐션을 제공한다. 단순히 설치만 하면된다.&lt;/p&gt;
&lt;figure class="media-caption align-center"&gt;&lt;img src="https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-2/image-001-optimized-image.webp" alt="" loading="lazy" width="480"&gt;
&lt;/figure&gt;
&lt;p&gt;로컬 LLM을 VS Code에서 사용하려면, 빌트인 되어있는 Copilot Chat 기능을 이용해야 한다. Copilot Chat의 UI와 코드 컨텍스트 수집 기능을 사용하고, 실제 응답을 생성하는 언어 모델은 Ollama에서 실행 중인 로컬 모델을 사용할 것이다.&lt;/p&gt;</description></item><item><title>Codeforces 1294C. Product of Three Numbers</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-1294c-product-of-three-numbers/</link><pubDate>Sat, 08 Aug 2026 22:41:23 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-1294c-product-of-three-numbers/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/1294/C"&gt;https://codeforces.com/problemset/problem/1294/C&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;테스트 케이스가 &lt;code&gt;t&lt;/code&gt;개 존재한다. 먼저, 정수 &lt;code&gt;n&lt;/code&gt;이 주어진다. 각 &lt;code&gt;n&lt;/code&gt;에 대해 $n = a \times b \times c, \ a, b, c &amp;gt; 1, \ a \neq b, b \neq c, a \neq c$를 만족하는 세 정수 &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;가 존재하면 &lt;code&gt;&amp;quot;YES&amp;quot;&lt;/code&gt;와 세 수를 출력하고, 그렇지 않으면 &lt;code&gt;&amp;quot;NO&amp;quot;&lt;/code&gt;를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;인수 분해 문제이다. &lt;code&gt;n&lt;/code&gt;이 3개의 정수의 곱으로 표현되어야 하는데, 3개의 정수가 서로소라는 제약조건은 없다. &lt;code&gt;64&lt;/code&gt;처럼 지수가 6이면 $64 = 2^1 \times 2^2 \times 2^3$ 처럼 표현할 수 있기 때문에 인수와 지수 둘 다 중요하다.&lt;/p&gt;</description></item><item><title>TIL. Aug 8, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-08/</link><pubDate>Sat, 08 Aug 2026 21:38:24 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-08/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3302-find-the-lexicographically-smallest-valid-sequence/"&gt;LeetCode 3302&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-1294c-product-of-three-numbers/"&gt;Codeforces 1294C&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stack Day의 컨셉과 MVP 범위 다시 정리&lt;/li&gt;
&lt;li&gt;기존에 작성하던 Stack Day 코드를 정리하고, 다음 구현을 위한 기준 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="leetcode-3302와-cpu-스케줄링"&gt;LeetCode 3302와 CPU 스케줄링&lt;/h3&gt;
&lt;p&gt;문제를 보면서 예전에 풀었던 CPU 스케줄링 문제가 연상됐다. CPU 스케줄링은 현재 들어온 작업만 보고 결정하면 최적의 결과를 만들기 어렵고, 앞으로 어떤 작업이 들어올지까지 알아야 한다.&lt;/p&gt;
&lt;p&gt;LeetCode 3302도 현재 인덱스에서 문자를 고를 때 뒤에 어떤 문자들이 남아 있는지를 알아야 했다. 실제 배열은 한 번에 주어지므로 미래를 기다릴 필요는 없지만, 인덱스 포인터의 시점에서는 뒤쪽 정보를 미리 알고 있어야 한다.&lt;/p&gt;</description></item><item><title>LeetCode 3302. Find the Lexicographically Smallest Valid Sequence</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3302-find-the-lexicographically-smallest-valid-sequence/</link><pubDate>Sat, 08 Aug 2026 21:06:44 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3302-find-the-lexicographically-smallest-valid-sequence/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-the-lexicographically-smallest-valid-sequence"&gt;https://leetcode.com/problems/find-the-lexicographically-smallest-valid-sequence&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;word1&lt;/code&gt;에서 인덱스를 고르고, 그 문자들로 &lt;code&gt;word2&lt;/code&gt;를 만들면 된다. 선택한 문자는 순서를 유지해야 하고, &lt;code&gt;word1&lt;/code&gt;의 문자 중 최대 하나는 다른 문자로 바꿔서 사용할 수 있다. 가능한 수열 중 인덱스가 사전순으로 가장 작은 것을 구하면 된다.&lt;/p&gt;
&lt;p&gt;앞에서부터 무조건 현재 문자가 같은지 확인하면서 고르면 되지만, 문자가 다른 위치에서 변경 기회를 바로 사용해도 뒤쪽에 남은 문자를 모두 맞출 수 있는지 확인해야 한다. 즉, 현재 위치를 선택했을 때 남은 문자의 개수가 충분해야 한다.&lt;/p&gt;</description></item><item><title>TIL. Aug 7, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-07/</link><pubDate>Fri, 07 Aug 2026 22:07:31 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-07/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;PS
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-459b-pashmak-and-flowers/"&gt;Codeforces 459B&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;dev-data-server-light
&lt;ul&gt;
&lt;li&gt;Auth 기능 추가&lt;/li&gt;
&lt;li&gt;에이전트 설정 정리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;블로그 클론 이후 Mermaid 재설치와 &lt;code&gt;npm audit&lt;/code&gt; 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="ai-에이전트-설정-문서의-역할"&gt;AI 에이전트 설정 문서의 역할&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;, Rule, Workflow, Skill의 역할을 다시 정리했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;: 프로젝트 구조, 아키텍처, 사용 기술처럼 항상 필요한 정보&lt;/li&gt;
&lt;li&gt;Rule: 프로젝트 전반에서 지켜야 하는 규칙&lt;/li&gt;
&lt;li&gt;Workflow: 반복 작업의 절차&lt;/li&gt;
&lt;li&gt;Skill: 특정 분야의 지식과 작업 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;모든 내용을 하나의 &lt;code&gt;AGENTS.md&lt;/code&gt;에 넣기보다, 에이전트가 현재 작업에 필요한 컨텍스트만 읽을 수 있도록 성격과 범위에 따라 나누는 편이 낫다.&lt;/p&gt;</description></item><item><title>Codeforces 459B. Pashmak and Flowers</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-459b-pashmak-and-flowers/</link><pubDate>Fri, 07 Aug 2026 20:55:17 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-459b-pashmak-and-flowers/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/459/B"&gt;https://codeforces.com/problemset/problem/459/B&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt;의 원소가 있는 수열 &lt;code&gt;b&lt;/code&gt;가 주어진다. &lt;code&gt;b&lt;/code&gt;의 원소 두 개를 짝지었을 때, 두 원소의 차이가 가장 클때의 그 차이와, 그 경우의 원소짝의 개수 출력하면 된다.&lt;/p&gt;
&lt;p&gt;경우의 수를 구하기 위해 &amp;lsquo;가장 큰 값&amp;rsquo;을 가진 원소의 개수와 &amp;lsquo;가장 작은 값&amp;rsquo;을 가진 원소의 개수를 구해야 한다. 가장 큰 값을 가진 원소의 개수를 $maxCount$, 가장 작은 값을 가진 원소의 개수를 $minCount$ 라고 했을 때, 경우의 수는 $maxCount \times minCount$로 어렵지 않게 구할 수 있다.&lt;/p&gt;</description></item><item><title>TIL. Aug 6, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-06/</link><pubDate>Thu, 06 Aug 2026 22:58:30 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-06/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3345-smallest-divisible-digit-product-i/"&gt;LeetCode 3345&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-489c-given-length-and-sum-of-digits/"&gt;Codeforces 489C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블로그 스크립트 구조화, &lt;code&gt;npm run&lt;/code&gt; 스크립트 정리&lt;/li&gt;
&lt;li&gt;StackDay 프로젝트 도메인, 데이터 모델, 유즈케이스, MVP 범위 정리&lt;/li&gt;
&lt;li&gt;Codex SKILL 공부&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="그리디-의심하기"&gt;그리디 의심하기&lt;/h3&gt;
&lt;p&gt;Codeforces 489C를 DP로 한참 구현하다가, 뒤늦게 그리디로 해결되는 문제라는 걸 알게 되었다.&lt;/p&gt;
&lt;p&gt;PS에서는 완전탐색 → 그리디 → DP 순서로 가능성을 검토하는 습관이 중요한 것 같다. 그리디가 최적인 것을 증명하는 연습이 더 필요하다는 것을 느꼈다. 경험을 통한 직관으로&amp;hellip;&lt;/p&gt;
&lt;h3 id="정책---도메인---데이터-모델---유즈케이스-순서로-사고하기"&gt;정책 -&amp;gt; 도메인 -&amp;gt; 데이터 모델 -&amp;gt; 유즈케이스 순서로 사고하기&lt;/h3&gt;
&lt;p&gt;Day Stack을 한번 뒤엎어야 했던 어제의 실패를 반면교사 삼아서, 이번엔 실제 구현에 들어가기 전에 도메인과 정책부터 제대로 잡으려 했다.&lt;/p&gt;</description></item><item><title>Codeforces 489C. Given Length and Sum of Digits</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-489c-given-length-and-sum-of-digits/</link><pubDate>Thu, 06 Aug 2026 13:40:23 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-489c-given-length-and-sum-of-digits/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/489/C"&gt;https://codeforces.com/problemset/problem/489/C&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;자리수가 &lt;code&gt;m&lt;/code&gt;이고 각 자리수의 합이 &lt;code&gt;s&lt;/code&gt;인 정수 중 가장 큰 수와 가장 작은 수를 찾는 문제이다.&lt;/p&gt;
&lt;p&gt;처음에는 DP로 접근했는데, DP로는 수의 개수 정도만 구할 수 있고, 최대값과 최소값을 찾기는 힘들 것 같았다. 그래서 다시 그리디로 접근했다.&lt;/p&gt;
&lt;p&gt;자리수가 &lt;code&gt;m&lt;/code&gt;인데 $1 &amp;lt;= m &amp;lt;= 100$ 이기 때문에, &lt;code&gt;int&lt;/code&gt; 타입으로 수를 다루는건 쉽지 않고, 배열이나 벡터로 다루는게 더 쉽다.&lt;/p&gt;
&lt;p&gt;최대값은 계수가 높은 쪽에 큰 숫자를 배치하고, 최소값은 계수가 낮은 쪽에 큰 숫자를 배치하는 방법을 사용하자.&lt;/p&gt;</description></item><item><title>Leetcode 3345. Smallest Divisible Digit Product I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3345-smallest-divisible-digit-product-i/</link><pubDate>Thu, 06 Aug 2026 13:32:20 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3345-smallest-divisible-digit-product-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/smallest-divisible-digit-product-i"&gt;https://leetcode.com/problems/smallest-divisible-digit-product-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt;보다 큰 수 중에서 각 자리수의 곱이 &lt;code&gt;t&lt;/code&gt;로 나눌 수 있는(나머지가 0인 ) 가장 작은 수를 리턴해야 한다.&lt;/p&gt;
&lt;p&gt;문제의 제약조건이 $1 &amp;lt;= n &amp;lt;= 100$, $1 &amp;lt;= t &amp;lt;= 10$ 이라서 모든 수를 찾아봐도 된다.&lt;/p&gt;
&lt;p&gt;정수의 각 자리수를 모두 곱한 수를 구하는 로직만 구현한 후에, &lt;code&gt;n&lt;/code&gt; 부터 시작해서 숫자를 1씩 증가시키면서 &lt;code&gt;t&lt;/code&gt;로 나눈 나머지를 구해서 찾으면 된다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;smallestNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;productDigits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;//=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;productDigits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>TIL. Aug 5, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-05/</link><pubDate>Wed, 05 Aug 2026 21:30:22 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-05/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3310-remove-methods-from-project/"&gt;LeetCode 3310&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-451b-sort-the-array/"&gt;Codeforces 451B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stack day 코드 뒤엎기&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="swift-bfs에서-조금-더-쉽게-큐-사용하기"&gt;Swift BFS에서 조금 더 쉽게 큐 사용하기&lt;/h3&gt;
&lt;p&gt;Swift에서 BFS 문제를 풀 때, 대부분 함수로 분리하고, &lt;code&gt;struct Queue { ... }&lt;/code&gt; 처럼 헤더 포인터 변수를 사용하는 유사 큐를 만들어서 썼다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;//... &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;//... &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;오늘 LeetCode 3310번 문제를 풀면서, 방문 체크 배열을 외부에서도 확인해야 하는 문제여서 &lt;code&gt;inout&lt;/code&gt;으로 넘기기 보다는, BFS 로직을 인라인으로 쓰는 방법을 했는데, 생각해보니 큐도 그냥 BFS 로직 안에 인라인으로 쓰면 되지 않나 라는 생각이 들었다.&lt;/p&gt;</description></item><item><title>LeetCode 3310. Remove Methods From Project</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3310-remove-methods-from-project/</link><pubDate>Wed, 05 Aug 2026 21:10:33 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3310-remove-methods-from-project/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/remove-methods-from-project"&gt;https://leetcode.com/problems/remove-methods-from-project&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;메소드 &lt;code&gt;k&lt;/code&gt;에서 시작해서 도달할 수 있는 노드들을 &amp;lsquo;suspicious&amp;rsquo; 하다고 했을 때, 이 &amp;lsquo;suspicious&amp;rsquo;한 메소드들을 &lt;code&gt;k&lt;/code&gt;가 직, 간접적으로 호출하는 것을 제외하고도 호출되는 경우가 있는지 확인하고 있다면 전체 메소드를, 없다면 &amp;lsquo;suspicious&amp;rsquo;한 메소드를 제외하고 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;메소드들의 호출 관계가 단방향 엣지 그래프를 이루기 때문에, BFS나 DFS 무엇을 써도 쉽게 &lt;code&gt;k&lt;/code&gt;가 직, 간접적으로 호출하는 함수들을 알 수 있다. &lt;code&gt;k&lt;/code&gt;에서 시작해서 도달하는 모든 메소드들은 &amp;lsquo;suspicious&amp;rsquo; 하기 때문에 방문 여부를 확인하는 배열을 그대로 사용하면 된다.&lt;/p&gt;</description></item><item><title>Codeforces 451B. Sort the Array</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-451b-sort-the-array/</link><pubDate>Wed, 05 Aug 2026 21:03:54 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-451b-sort-the-array/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/451/B"&gt;https://codeforces.com/problemset/problem/451/B&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt; 크기 수열 &lt;code&gt;a&lt;/code&gt;가 주어진다. 이 수열의 특정 구간을 선택해서 뒤집는 것을 1번 했을 때, 이 수열이 오름차순으로 정렬되어 있다면 &lt;code&gt;&amp;quot;yes&amp;quot;&lt;/code&gt;와 그 구간을, 불가능하면 &lt;code&gt;&amp;quot;no&amp;quot;&lt;/code&gt;를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt;의 제약 조건이 $1 &amp;lt;= n &amp;lt;= 10^5$ 이기 때문에, 브루트 포스로는 시간 내에 풀기 힘들다.&lt;/p&gt;
&lt;p&gt;특정 구간을 선택해서 뒤집는 행동을 1번만 한다는 것이 힌트인데, 구간 하나를 1번 뒤집어서 수열 전체가 오름차순이 된다는 것은, 수열의 일부 구간만 내림차순 이라는 것이다.&lt;/p&gt;</description></item><item><title>TIL. Aug 4, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-04/</link><pubDate>Tue, 04 Aug 2026 23:50:02 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-04/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3731-find-missing-elements/"&gt;LeetCode 3731&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-580c-kefa-and-park/"&gt;Codeforces 580c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블로그 레이아웃, 숏코드, 콘텐츠, 스크립트, 기능 정리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ps"&gt;ps&lt;/h2&gt;
&lt;p&gt;Codeforces 580c가 그래프(트리)를 순회하는 문제였는데, 각 노드의 값이 0 혹은 1이라서 &lt;code&gt;bool&lt;/code&gt; 타입 벡터를 사용하고 입력을 받으려 했다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nl"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;아무런 이상이 없는 코드라고 생각했지만, 컴파일 에러가 생겼다. 이유를 조금 찾아보고 정리를 했는데 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;bool&lt;/code&gt; 타입을 원소로 가지는 벡터는 다른 벡터들과 다르게 각 원소를 1비트 단위로 압축해서 저장한다. (ex: &lt;code&gt;1010101...&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;압축되어 저장되었기 때문에(그냥 비트에 녹아버렸으니까) 다른 타입의 벡터와 서브스크립트 접근 방식이 달라야 한다.&lt;/li&gt;
&lt;li&gt;이를 해결하기 위해서 프록시 객체가 존재한다. &lt;code&gt;a[3] = true;&lt;/code&gt; -&amp;gt; &lt;code&gt;a.operator[](3).operator=(true);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;만약 &lt;code&gt;bool&amp;amp;&lt;/code&gt;을 통해 레퍼런스를 뽑아내려 하면, 프록시 객체 자체가 리턴된다.&lt;/li&gt;
&lt;li&gt;결론적으로 &lt;code&gt;vector&amp;lt;bool&amp;gt;&lt;/code&gt;에선 위의 코드같은 문법을 못 쓴다&amp;hellip;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;위와 같은 경우가 아니더라도, 굳이 &lt;code&gt;bool&lt;/code&gt; 타입 벡터를 쓸 필요도 없는게, 프록시 객체가 원소를 뽑아오는 것도 다른 벡터보다 더 많은 계산 시간이 필요하다. 그래서 그냥 &lt;code&gt;int&lt;/code&gt; 벡터로 문제를 풀었다.&lt;/p&gt;</description></item><item><title>Codeforces 580C. Kefa and Park</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-580c-kefa-and-park/</link><pubDate>Tue, 04 Aug 2026 11:34:01 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-580c-kefa-and-park/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/580/C"&gt;https://codeforces.com/problemset/problem/580/C&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;노드의 값이 &lt;code&gt;1&lt;/code&gt; 혹은 &lt;code&gt;0&lt;/code&gt;인 트리 그래프와 그 크기인 정수 &lt;code&gt;n&lt;/code&gt;이 주어진다. 루트 노드인 1번 노드에서 시작했을 때, 중간에 값이 1인 노드를 연속으로 &lt;code&gt;m&lt;/code&gt;번을 초과해서 만날 수 없다. 이 때, 도달할 수 있는 리프 노드의 개수를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;트리 전체를 탐색하면서 연속으로 조우한 값이 1인 노드 개수를 관리하면 된다. 그리고 현재 방문한 노드가 리프 노드인지 판정하고, 만약 리프 노드면 1을 더하면 된다. 트리도 그래프이기 때문에, BFS, DFS 어느 쪽이든 가능하지만, 풀이를 할 때 DFS를 사용했다.&lt;/p&gt;</description></item><item><title>LeetCode 3731. Find Missing Elements</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3731-find-missing-elements/</link><pubDate>Tue, 04 Aug 2026 09:33:33 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3731-find-missing-elements/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-missing-elements"&gt;https://leetcode.com/problems/find-missing-elements&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;연속된 정수 구간에 속한 모든 정수가 들어 있&amp;rsquo;던&amp;rsquo; 수열 &lt;code&gt;nums&lt;/code&gt;가 주어진다. 일부 원소가 사라진 상태인 상태인데, 이 사라진 원소들을 배열에 오름차순으로 담아 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;최대값과 최소값은 사라지지 않았다고 하니까, 정수 구간의 크기를 구할 수 있다. 그 정수 구간을 순회하면서 빠진 원소들을 찾으면 된다.&lt;/p&gt;
&lt;p&gt;정렬을 이용해서 풀 수도 있는데, 이러면 시간 복잡도가 평균 $O(n \times \log n)$이 된다. 큰 차이는 안나지만 Hast Set을 이용하면 평균 $O(n)$에 풀 수 있다.&lt;/p&gt;</description></item><item><title>TIL. Aug 3, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-08-03/</link><pubDate>Mon, 03 Aug 2026 23:31:07 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-08-03/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LeetCode 1406 Stone Game III&lt;/li&gt;
&lt;li&gt;Codeforces 520B Two Buttons&lt;/li&gt;
&lt;li&gt;WWDC &lt;code&gt;Meet async/await in Swift&lt;/code&gt; 세션 시청 및 정리.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="ps"&gt;PS&lt;/h3&gt;
&lt;p&gt;LeetCode 1406은 현재 차례인 플레이어가 상대보다 확보할 수 있는 최대 점수 차이를 DP로 정의해 풀었다. 누가 Alice인지 Bob인지에 따라 상태를 나누지 않아도, 현재 상태를 점수 차이로 표현하면 같은 점화식으로 문제를 풀 수 있다.&lt;/p&gt;
&lt;p&gt;점화식이 안떠올라서 힌트를 보고 풀었다.&lt;/p&gt;
&lt;p&gt;Codeforces 520B는 두 연산을 그래프의 간선으로 보고 BFS로 최단 거리를 구했다. 다만 목표값이 시작값보다 작을 때는 2배 연산이 도움이 되지 않으므로, 단순히 1씩 감소시키는 경우를 분리해 처리했다.&lt;/p&gt;</description></item><item><title>Swift Concurrency. Meet async/await in Swift (2) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-meet-async-await-in-swift-2/</link><pubDate>Mon, 03 Aug 2026 23:01:47 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-meet-async-await-in-swift-2/</guid><description>&lt;p&gt;1편에서는 async await를 어떻게 사용했는지 알아봤다면, 여기서는 테스트와 실제 앱 코드에서 async/await를 사용하는 법을 알아본다. 또한 기존에 존재하는 completion handler 기반 API를 continuation을 사용하여, async/await를 사용하는 async alternative로 변환하는 방법을 알아본다.&lt;/p&gt;
&lt;h2 id="비동기-코드-테스트하기"&gt;비동기 코드 테스트하기&lt;/h2&gt;
&lt;p&gt;async/await를 쓰면 비동기 코드도 동기 코드만큼 쉽게 테스트할 수 있다. XCTest는 &lt;code&gt;async&lt;/code&gt; 테스트를 지원한다.&lt;/p&gt;
&lt;p&gt;아래는 completion handler 방식의 비동기 코드를 테스트하는 코드이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MockViewModelSpec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;XCTestCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;testFetchThumbnails&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;expectation&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;XCTestExpectation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;mock thumbnails completion&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mockViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fetchThumbnail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;mockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;XCTAssertNil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;expectation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fulfill&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;expectation&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;aside class="callout" data-callout="note"&gt;
&lt;div class="callout__header"&gt;&lt;span class="callout__icon" aria-hidden="true"&gt;i&lt;/span&gt;&lt;span class="callout__title"&gt;fulfill&lt;/span&gt;
&lt;/div&gt;
&lt;div class="callout__body"&gt;&lt;code&gt;fulfill()&lt;/code&gt;은 expectation을 충족된 상태로 표시하는 메소드다. 일반적으로 비동기 작업이 완료되었을 때 호출한다.&lt;/div&gt;
&lt;/aside&gt;
&lt;p&gt;기존에는 &lt;code&gt;XCTestExpectation&lt;/code&gt;을 만들고, API를 호출한 뒤 expectation을 fulfill 하고, 지정한 시간 동안 기다리도록 작성해야 했다.&lt;/p&gt;</description></item><item><title>Swift Concurrency. Meet async/await in Swift (1) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-meet-async-await-in-swift-1/</link><pubDate>Mon, 03 Aug 2026 20:03:38 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-meet-async-await-in-swift-1/</guid><description>&lt;p&gt;completion handler로 작성한 비동기 코드는 쉽게 장황해지고, 복잡해지고, 부정확해진다.&lt;/p&gt;
&lt;p&gt;Swift의 async/await는 비동기 코드를 일반 코드를 작성하는 것처럼 만들어 주고, 아이디어를 더 쉽게 반영하며, 더 안전하게 만든다.&lt;/p&gt;
&lt;p&gt;async/await는 단순한 비동기 표현 방식이 아니다. 이 세션에서는 async/await가 왜 기존 completion handler 방식보다 좋은지, 그리고 Swift의 컨셉에 왜 잘 맞는지를 계속해서 설명한다.&lt;/p&gt;
&lt;h2 id="meet-asyncawait-in-swift"&gt;Meet async/await in Swift&lt;/h2&gt;
&lt;p&gt;Foundation 같은 Apple SDK에는 &lt;code&gt;await&lt;/code&gt;할 수 있는 수백 개의 메소드가 존재한다. UIKit의 &lt;code&gt;UIImage&lt;/code&gt;는 섬네일을 만드는 API를 동기 방식과 비동기 방식으로 모두 제공한다.&lt;/p&gt;</description></item><item><title>Codeforces 520B. Two Buttons</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-520b-two-buttons/</link><pubDate>Mon, 03 Aug 2026 13:30:19 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-520b-two-buttons/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/520/B"&gt;https://codeforces.com/problemset/problem/520/B&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정수 &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt;이 주어지고, 연산 2개 (* 2, - 1)을 이용해서 &lt;code&gt;n&lt;/code&gt;을 &lt;code&gt;m&lt;/code&gt;으로 만드는데 필요한 연산의 최소 개수를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;$1 &amp;lt;= n, m &amp;lt;= 10^4$ 제약조건과 2배로 만드는 연산을 생각해보면 만들 수 있는 숫자의 개수는 최대 2만개 정도이다. 이 숫자들을 각각을 노드라 생각하면, 연산으로 정의되는 노드간 연결도 명확한 그래프로 생각할 수 있다.&lt;/p&gt;
&lt;p&gt;그러면 이 문제는 최단 거리 문제가 되므로 BFS를 사용해서 쉽게 풀 수 있다. 2배 연산이 있으므로 방문 확인 배열의 크기를 m * 2로 잡고 BFS를 하면된다. (방문 확인 배열도 할 겸 거리를 세는 기능도 넣으면 좋다.)&lt;/p&gt;</description></item><item><title>Leetcode 1406. Stone Game III</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1406-stone-game-iii/</link><pubDate>Mon, 03 Aug 2026 12:31:05 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1406-stone-game-iii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/stone-game-iii"&gt;https://leetcode.com/problems/stone-game-iii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;번호가 적힌 돌이 있고, 두 명(Alice, Bob)이 번갈아 가면서 그 돌을 1개에서 3개까지 가져갈 수 있다. 2명 다 이상적으로 플레이 했을 때, 돌에 적힌 번호를 더한 합이 더 많이 가져간 사람의 이름을 리턴하면 된다. 항상 Alice가 먼저 시작한다.&lt;/p&gt;
&lt;p&gt;약간 특이한 DP 문제이다. 점화식을 &amp;lsquo;Alice&amp;rsquo; &amp;lsquo;Bob&amp;rsquo;을 특정하지 않고 &amp;lsquo;현재 차례인 사람이 상대보다 돌을 가질 수 있는 최대 개수&amp;rsquo;로 정의해야한다.&lt;/p&gt;
&lt;p&gt;점화식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$
dp[i] = \max \begin{cases} stoneValue[i] - dp[i+1] \\ stoneValue[i] + stoneValue[i+1] - dp[i+2] \\ stoneValue[i] + stoneValue[i+1] + stoneValue[i+2] - dp[i+3] \end{cases}
$$&lt;/p&gt;</description></item><item><title>TIL. Jul 31, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-31/</link><pubDate>Fri, 31 Jul 2026 21:00:57 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-31/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LeetCode 3016, LeetCode 1979 풀이&lt;/li&gt;
&lt;li&gt;Codeforces 455A 풀이&lt;/li&gt;
&lt;li&gt;AGENTS.md, SKILL.md 관련 자료 학습&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="ps"&gt;PS&lt;/h3&gt;
&lt;p&gt;LeetCode 3016은 3014와 풀이가 동일했다. 문제의 제약 조건은 달랐지만, 3014를 풀 당시 더 큰 제약까지 고려해서 구현해 두었던 덕분에 그대로 통과할 수 있었다. 왜인지 3014가 Easy 문제치고는 생각보다 까다로운 편이었다.&lt;/p&gt;
&lt;p&gt;Codeforces 455A는 전형적인 DP 문제였다. 다만 C++에서는 정수 범위를 고려해 &lt;code&gt;long long&lt;/code&gt;을 사용해야 하는데, Swift와 Python만 주로 사용하다 보니 이 부분을 자주 놓치는 것 같다.&lt;/p&gt;</description></item><item><title>Leetcode 1979. Find Greatest Common Divisor of Array</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1979-find-greatest-common-divisor-of-array/</link><pubDate>Fri, 31 Jul 2026 20:36:12 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1979-find-greatest-common-divisor-of-array/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-greatest-common-divisor-of-array"&gt;https://leetcode.com/problems/find-greatest-common-divisor-of-array&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;수열 &lt;code&gt;nums&lt;/code&gt;의 원소 중 가장 큰 원소의 가장 작은 원소의 GCD를 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;처음에 &lt;code&gt;max()&lt;/code&gt;와 &lt;code&gt;min()&lt;/code&gt;을 썼는데, 제출 시간이 거의 최하위권이길래 for loop로 다시 작성했다.&lt;/p&gt;
&lt;p&gt;GCD 자체는 유클리드 호제법을 이용해서 구한다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;findGCD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;min&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;max&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;max&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;min&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;min&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;min&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;max&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;max&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;max&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;gcd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Codeforces 455A. Boredom</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-455a-boredom/</link><pubDate>Fri, 31 Jul 2026 20:22:51 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-455a-boredom/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/455/A"&gt;https://codeforces.com/problemset/problem/455/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;풀이&lt;/p&gt;
&lt;p&gt;배열&lt;code&gt;a&lt;/code&gt;에서 얻을 수 있는 최대 점수를 구하는 DP 문제이다. 어떤 값 &lt;code&gt;x&lt;/code&gt;를 선택하면 &lt;code&gt;x&lt;/code&gt;만큼의 점수를 얻고, 배열에 있는 x - 1과 x + 1은 모두 제거된다.&lt;/p&gt;
&lt;p&gt;여기서 중요한 점은 같은 값을 여러 개 가지고 있다면 하나씩 선택할 이유가 없다는 것이다. &lt;code&gt;x&lt;/code&gt;를 선택하는 순간 &lt;code&gt;x - 1&lt;/code&gt;과 &lt;code&gt;x + 1&lt;/code&gt;은 모두 사용할 수 없으므로, 선택한다면 값이 &lt;code&gt;x&lt;/code&gt;인 원소는 모두 선택하는 것이 항상 이득이다.&lt;/p&gt;
&lt;p&gt;따라서 입력 배열의 순서는 의미가 없어지고, 각 숫자가 몇 번 등장하는지만 알면 된다. 값 &lt;code&gt;x&lt;/code&gt;가 &lt;code&gt;frequencies[x]&lt;/code&gt;번 등장한다면, x를 선택했을 때 얻는 점수는 &lt;code&gt;x * frequencies[x]&lt;/code&gt;이다.&lt;/p&gt;</description></item><item><title>TIL. Jul 30, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-30/</link><pubDate>Thu, 30 Jul 2026 23:19:17 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-30/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-279b-books/"&gt;Codeforces 279B&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3014-minimum-numbers-of-pushes-to-type-word-i/"&gt;LeetCode 3014&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;과거 Bicubic, Smart CCTV 프로젝트 정리&lt;/li&gt;
&lt;li&gt;미방문록 회의, AGENTS 수정.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="skill-사용하기"&gt;SKILL 사용하기&lt;/h3&gt;
&lt;p&gt;프로젝트를 진행하면서 기본적인 개발 원칙은 AGENTS.md에 정리했다. 하지만 View, ViewModel, Test처럼 반복해서 만드는 코드까지 모두 AGENTS.md에 작성하는 것은 적절하지 않았다.&lt;/p&gt;
&lt;p&gt;이런 작업은 프로젝트의 규칙이라기보다 반복 작업의 절차에 가깝기 때문이다.&lt;/p&gt;
&lt;p&gt;예를 들어 View를 생성할 때는 ViewModel을 어떻게 주입할지, Preview를 어떻게 작성할지 등 항상 비슷한 패턴을 따른다. ViewModel이나 테스트 코드도 마찬가지다.&lt;/p&gt;</description></item><item><title>Codeforces 279B. Books</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-279b-books/</link><pubDate>Thu, 30 Jul 2026 23:08:53 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-279b-books/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/279/B"&gt;https://codeforces.com/problemset/problem/279/B&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;책을 읽는데 걸리는 시간이 담긴 크기 &lt;code&gt;n&lt;/code&gt; 배열 &lt;code&gt;a&lt;/code&gt;가 주어지고, 책을 읽을 수 있는 시간 &lt;code&gt;t&lt;/code&gt;가 주어진다. 특정 인덱스를 정해서 그 인덱스부터 책을 순서대로 읽었을때, 최대로 읽을 수 있는 책의 개수를 출력하면된다.&lt;/p&gt;
&lt;p&gt;모든 경우의 수를 탐색하려면 $O(n^2)$의 시간 복잡도를 가지는데 책의 개수가 10만개 이므로, 시간 내로 해결하기는 힘들다.&lt;/p&gt;
&lt;p&gt;&amp;lsquo;순서대로&amp;rsquo;라는 조건이 있으므로, 투 포인터를 이용하면 쉽게 풀 수 있다.&lt;/p&gt;
&lt;p&gt;단 배열 &lt;code&gt;a&lt;/code&gt;의 원소의 크기가 &lt;code&gt;t&lt;/code&gt;보다 클 수 있으므로, 단 한권의 책도 읽지 못하는 경우가 있다. 그래서 책을 0권 읽는 경우의 수도 생각해서 코드를 짜야 한다.&lt;/p&gt;</description></item><item><title>Leetcode 3014. Minimum Numbers of Pushes to Type Word I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3014-minimum-numbers-of-pushes-to-type-word-i/</link><pubDate>Thu, 30 Jul 2026 22:58:21 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3014-minimum-numbers-of-pushes-to-type-word-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/minimum-number-of-pushes-to-type-word-i"&gt;https://leetcode.com/problems/minimum-number-of-pushes-to-type-word-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;휴대전화의 2에서 8까지의 숫자에 문자를 배치할 수 있고, 2개 이상의 수가 배치되었을 땐 여러번 눌러야 뒤에 있는 숫자를 타이핑 할 수 있다. 스트링 &lt;code&gt;word&lt;/code&gt;가 주어졌을 때, 버튼을 가장 적게 눌러 &lt;code&gt;word&lt;/code&gt;를 타이핑 했을 때의 타이핑 수를 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;각 키의 첫 번째 문자는 1번, 두 번째는 2번&amp;hellip; 눌러야 하므로 많이 등장하는 문자일수록 누름 횟수가 적은 앞자리에 배치해야 한다.&lt;/p&gt;
&lt;p&gt;빈도수 내림차순 정렬 후, 인덱스를 8로 나눈 몫 + 1이 해당 문자의 누름 횟수가 된다.&lt;/p&gt;</description></item><item><title>TIL. Jul 29, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-29/</link><pubDate>Wed, 29 Jul 2026 20:53:29 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-29/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3518-smallest-palindromic-rearrangement-ii/"&gt;LeetCode 3518: Smallest Palindromic Rearrangement II&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-189a-cut-ribbon/"&gt;Codeforces 189A: Cut Ribbon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;블로그 깃 훅 제거&lt;/li&gt;
&lt;li&gt;블로그 스크립트 구조화&lt;/li&gt;
&lt;li&gt;블로그 커밋 목록 정리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="해결-내용"&gt;해결 내용&lt;/h2&gt;
&lt;p&gt;PS 두 문제를 푼 이후에, 블로그에서 스크립트와 깃 훅을 교체하고, 하루종일 깃과 씨름했다. Hugo 프로젝트의 커밋 로그가 너무 더러웠고, Squash, Rebase로 한 번 정리하려는데, 중간에 워킹 트리가 한번 꼬여버렸다.&lt;/p&gt;
&lt;h3 id="블로그-깃-훅-일시-제거"&gt;블로그 깃 훅 일시 제거.&lt;/h3&gt;
&lt;p&gt;블로그 깃 훅에는 두 가지 문제가 있다. 첫 번째는 타이밍 문제다. pre-commit에 뭔가 내용을 수정하는 훅을 넣으면, 커밋이 멈추지 않고. 변경사항을 유지한채로 커밋되어버린다.&lt;/p&gt;</description></item><item><title>Codeforces 189A. Cut Ribbon</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-189a-cut-ribbon/</link><pubDate>Wed, 29 Jul 2026 10:55:29 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-189a-cut-ribbon/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/189/A"&gt;https://codeforces.com/problemset/problem/189/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;길이가 &lt;code&gt;n&lt;/code&gt;인 리본이 하나 주어지고, 이를 &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt; 의 크기로만 조각낼 수 있을 때, 최대로 만들 수 있는 조각의 개수를 출력하는 문제이다.&lt;/p&gt;
&lt;p&gt;잘린 리본 조각의 크기가 정해져 있으므로, 그리디가 아니라 DP로 접근해야 한다. 그리디로 접근하면 마지막에 남은 리본 조각의 크기를 확정할 수 없기 때문이다. &lt;code&gt;dp[i]&lt;/code&gt;를 길이 &lt;code&gt;i&lt;/code&gt;인 리본을 조각냈을 때의 최대 조각 수로 정의하면, 점화식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;$$dp[i] = \max_{x \in {a, b, c}}(dp[i - x] + 1) \quad \text{if } i \geq x \text{ and } dp[i-x] \neq -1$$&lt;/p&gt;</description></item><item><title>LeetCode 3518. Smallest Palindromic Rearrangement II</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3518-smallest-palindromic-rearrangement-ii/</link><pubDate>Wed, 29 Jul 2026 10:36:59 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3518-smallest-palindromic-rearrangement-ii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/smallest-palindromic-rearrangement-ii"&gt;https://leetcode.com/problems/smallest-palindromic-rearrangement-ii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3517-smallest-palindromic-rearrangement-i/"&gt;1번 문제&lt;/a&gt;와 마찬가지로 팰린드롬의 성질상 절반만 결정하면 전체가 결정된다. 따라서 이 문제는 절반 문자열의 &lt;code&gt;k&lt;/code&gt;번째 사전순 순열을 구하는 문제로 단순화된다.&lt;/p&gt;
&lt;p&gt;각 문자의 등장 횟수를 세고, 홀수 번 등장하는 문자는 팰린드롬의 가운데에 배치한다. 나머지는 2로 나눠 &lt;code&gt;halfTable&lt;/code&gt;을 만든다. 절반 문자열에는 중복 문자가 있을 수 있으므로, 전체 순열 수는 단순히 $n!$이 아니라 중복 순열 공식으로 구해야 한다.&lt;/p&gt;
&lt;p&gt;$$\frac{n!}{\prod_{i} n_i!}$$&lt;/p&gt;
&lt;p&gt;여기서 &lt;code&gt;n&lt;/code&gt;은 절반 문자열의 길이, &lt;code&gt;n_i&lt;/code&gt;는 각 문자의 개수이다. 이 값이 &lt;code&gt;k&lt;/code&gt;보다 작으면 &lt;code&gt;k&lt;/code&gt;번째 순열이 존재하지 않으므로 빈 문자열을 반환한다.&lt;/p&gt;</description></item><item><title>TIL. Jul 28, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-28/</link><pubDate>Tue, 28 Jul 2026 21:09:14 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-28/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-230b-t-primes/"&gt;Codeforces 230B. T-Primes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3517-smallest-palindromic-rearrangement-i/"&gt;Leetcode 3517. Smallest Palindromic Rearrangement I&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="c-배열-vs-벡터"&gt;C++ 배열 vs 벡터&lt;/h3&gt;
&lt;p&gt;Codeforces에서는 C++로만 코드를 작성하는데, 최근에는 벡터보다 C 스타일 배열을 선호했다. 그런데 오늘 T-Primes 문제를 풀면서 다시 벡터를 쓸까 고민했다.&lt;/p&gt;
&lt;p&gt;가장 큰 이유는 보일러플레이트 때문이다. &lt;code&gt;push_back&lt;/code&gt; 같은 벡터에서 편리한, 다른 언어에서는 당연히 있는 메소드가 배열에 없다. 결국 추가 코드를 작성하고 어느정도의 비효율이 생긴다. 그 외에도 배열은 함수에 넘길 때 크기를 같이 넘겨줘야 하는 번거로움이 있다. 글로벌 변수를 선호하지 않아서 레퍼런스를 파라미터로 와르르 넘기는 스타일을 쓰는데, 배열이면 크기도 같이 들고 다녀야 한다.&lt;/p&gt;</description></item><item><title>Codeforces 230B. T-Primes</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-230b-t-primes/</link><pubDate>Tue, 28 Jul 2026 10:39:27 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-230b-t-primes/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/230/B"&gt;https://codeforces.com/problemset/problem/230/B&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;T-Prime을 약수가 3개인 수라고 정의하고, $n$개의 크기의 수열 $x$의 원소 각각에 대해서 그 수가 T-Prime인지 확인하는 문제이다.&lt;/p&gt;
&lt;p&gt;약수가 3개라는 뜻은, $1$과 자기 자신 그리고 $\sqrt{x_i}$만을 약수로 가진다는 뜻이다. 즉, T-Prime은 어떤 수의 제곱이어야 한다.&lt;/p&gt;
&lt;p&gt;그 &amp;lsquo;어떤 수&amp;rsquo;의 조건은 무엇일까? 약수의 약수는 결국 약수이다. T-Prime은 $1$, &amp;lsquo;어떤 수&amp;rsquo;, 자기 자신만을 약수로 가지므로, &amp;lsquo;어떤 수&amp;rsquo;는 소수여야 한다. 결국 이 문제는 소수 판별 문제로 단순화된다.&lt;/p&gt;
&lt;p&gt;$x_i$의 최댓값이 $10^{12}$이지만, T-Prime 여부를 판별하려면 $\sqrt{x_i}$가 소수인지만 확인하면 되므로 체는 $\sqrt{10^{12}} = 10^6$까지만 구성하면 충분하다. 에라토스테네스의 체의 시간복잡도는 (거의) $O(N)$이고, 이후 각 쿼리는 $O(1)$에 처리되므로, $n \leq 10^5$인 입력 전체에 대해 전처리 $O(10^6)$ + 쿼리 $O(n)$으로 풀 수 있다.&lt;/p&gt;</description></item><item><title>Leetcode 3517. Smallest Palindromic Rearrangement I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3517-smallest-palindromic-rearrangement-i/</link><pubDate>Tue, 28 Jul 2026 09:12:06 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3517-smallest-palindromic-rearrangement-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/smallest-palindromic-rearrangement-i"&gt;https://leetcode.com/problems/smallest-palindromic-rearrangement-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;팰린드롬 스트링 &lt;code&gt;s&lt;/code&gt;가 주어지고, 이 &lt;code&gt;s&lt;/code&gt;의 원소들을 재배열 하여 만들 수 있는 팰린드롬중 가장 사전순으로 빠른 문자열을 리턴하는 문제이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;s&lt;/code&gt;가 팰린드롬 스트링인것이 보장되니, 팰린드롬의 성질인 대칭을 이용하면 정렬 문제로 바꿀 수 있다. &lt;code&gt;s&lt;/code&gt;의 원소 개수가 홀수인지 짝수인지만 주의하면 된다. 만약 홀수면 대칭의 중심이 존재하니, 원소 중 등장 횟수가 홀수인 원소가 존재한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;에서 등장하는 모든 원소의 등장 횟수를 센다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;s&lt;/code&gt;의 원소 개수가 홀수라면, 원소들 중 홀수번 등장하는 원소를 &lt;code&gt;center&lt;/code&gt;를 찾는다. 이 원소가 팰린드롬의 중간에 들어가는 문자이다.&lt;/li&gt;
&lt;li&gt;원소들의 등장 횟수를 절반으로 줄인 다음, 사전 오름차순으로 정렬한 스트링 &lt;code&gt;half&lt;/code&gt;를 만든다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;half&lt;/code&gt;와 &lt;code&gt;center&lt;/code&gt; 그리고 &lt;code&gt;half&lt;/code&gt;를 뒤집은 스트링을 합쳐서 결과를 만든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;smallestPalindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;countTable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Character&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;half&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;center&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;countTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;countTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;center&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;half&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;half&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;center&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;half&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>SwiftUI. Essentials - WWDC24</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-essentials/</link><pubDate>Mon, 27 Jul 2026 22:18:58 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-essentials/</guid><description>&lt;p&gt;SwiftUI는 선언형 UI 프레임워크다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rich Feature Set, 다양한 기능과 기기 고유의 이점을 활용할 수 있는 풍부한 기능 집합&lt;/li&gt;
&lt;li&gt;Less Code, 더 적은 코드&lt;/li&gt;
&lt;li&gt;Incremental adoption, 필요한 순간에 적절하게 사용 가능. 전체 앱이 반드시 SwiftUI일 필요는 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="swiftui-essentials"&gt;SwiftUI Essentials&lt;/h3&gt;
&lt;p&gt;SwiftUI는 선언형 UI 프레임워크이기 때문에 UIKit 처럼 &lt;code&gt;UIView&lt;/code&gt; 객체가 계속 메모리에 상주해있고, 그 객체를 직접 변화시키는게 아니라, &lt;code&gt;View&lt;/code&gt;를 보고 SwiftUI가 그리는 방식이다. 즉, &lt;code&gt;View&lt;/code&gt;는 그냥 UI 요소를 정의하는 설계도이다. (Demistify SwiftUI 세션에서도 한 말이다!)&lt;/p&gt;</description></item><item><title>TIL. Jul 27, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-27/</link><pubDate>Mon, 27 Jul 2026 21:32:08 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-27/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-4c-registration-system/"&gt;Codeforces 4C. Registration System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-codeforces-25a-iq-test/"&gt;Codeforces 25A. IQ Test&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;각각 Hash Table과 구현 능력을 요구하는 PS 문제였다. IQ Test 부분이 구현이 살짝 번거로운 부분이 있었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/wwdc-swiftui-essentials/"&gt;SwiftUI. SwiftUI Essentials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WWDC 24에서 나온 SwiftUI Essentials 세션을 봤다. 24분 영상인데 정보 밀도가 엄청 높고 예제에서 보여준 것들도 많아서, 직접 예제를 돌리고 캡처하고, 동영상 녹화하고 하는데 꽤 시간이 들었다.&lt;/p&gt;
&lt;p&gt;덕분에 블로그에 이미지 수평 배열, 이미지 캡션과 같은 숏 코드들도 추가했다.&lt;/p&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="swiftui-essentials"&gt;SwiftUI Essentials&lt;/h3&gt;
&lt;p&gt;WWDC 세션을 하나 봤다. 이번에는 SwiftUI의 기본 구조를 다시 정리하는 내용이었는데, 핵심은 &lt;code&gt;View&lt;/code&gt;가 실제 UI 객체를 직접 만지는 대상이 아니라 선언형으로 UI를 설명하는 값이라는 점 이었다(Demystify SwiftUI도 마찬가지고 엄청나게 반복되는 내용이다.)&lt;/p&gt;</description></item><item><title>Codeforces 25A. IQ Test</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-25a-iq-test/</link><pubDate>Mon, 27 Jul 2026 16:26:14 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-25a-iq-test/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/25/A"&gt;https://codeforces.com/problemset/problem/25/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt; 개의 원소를 가진 수열이 입력으로 들어오고 입력으로 들어온 숫자 중 홀/짝이 다른 하나의 숫자의 인덱스(1-base 인덱스)를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;수열이 들어올 때마다 홀/짝 각각의 마지막 인덱스를 저장하고, 홀수의 개수, 짝수의 개수를 세면된다.&lt;/p&gt;
&lt;p&gt;마지막 이렇게 얻어진 개수로 홀/짝인지 판별을 한 뒤에, 홀수면 짝수의, 짝수면 홀수의 마지막 인덱스를 출력하면 된다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oddCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;evenCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;oddIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;evenIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;evenCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;evenIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;oddCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;oddIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oddCount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="nl"&gt;oddIndex&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;evenIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Codeforces 4C. Registration System</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-4c-registration-system/</link><pubDate>Mon, 27 Jul 2026 11:07:19 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-4c-registration-system/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/4/C"&gt;https://codeforces.com/problemset/problem/4/C&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;데이터베이스를 흉내내는 문제이다. &lt;code&gt;n&lt;/code&gt; 개의 스트링이 입력으로 주어지고(각각의 스트링을 &lt;code&gt;name&lt;/code&gt; 이라고 한다), 그 스트링이 만약 등록된 이름이면 이름 + 번호를 붙여서 출력하고 등록되지 않은 이름이면 &lt;code&gt;'OK'&lt;/code&gt;를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;딕셔너리를 쓰면 가장 쉽게 해결 가능하다. 딕셔너리에 &lt;code&gt;name&lt;/code&gt;을 키로, 그리고 등장한 횟수를 값으로 저장하면 쉽게 존재 판별과 번호 붙이기 둘 다 가능하다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;map&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;OK&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Leetcode 1464. Maximum Product of Two Element in an Array</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1464-maximum-product-of-two-element-in-an-array/</link><pubDate>Sun, 26 Jul 2026 10:34:58 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1464-maximum-product-of-two-element-in-an-array/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/maximum-product-of-three-numbers"&gt;https://leetcode.com/problems/maximum-product-of-three-numbers&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정수형 배열 &lt;code&gt;nums&lt;/code&gt; 안에서 세 개의 수를 뽑아 곱한 값 중 최대값을 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-3536-maximum-product-of-two-digits/"&gt;LeetCode 3536&lt;/a&gt; 3536번 문제처럼 &lt;code&gt;nums&lt;/code&gt; 배열을 정렬하면 된다. 다만 이번에는 3개의 수를 뽑아야 하기에, 음수, 음수, 양수도 정답의 후보가 될 수 있다.&lt;/p&gt;
&lt;p&gt;따라서 정답의 후보는 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;가장 작은 값 2개와 가장 큰 값 1개를 곱한 값&lt;/li&gt;
&lt;li&gt;가장 큰 값 3개를 곱한 값&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 두 수를 계산한 다음, 대소를 비교해서 리턴하면 된다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;maximumProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Leetcode 3536. Maximum Product of Two Digits</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3536-maximum-product-of-two-digits/</link><pubDate>Sat, 25 Jul 2026 21:13:47 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3536-maximum-product-of-two-digits/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/maximum-product-of-two-digits"&gt;https://leetcode.com/problems/maximum-product-of-two-digits&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;10 이상 10억 이하의 정수 &lt;code&gt;n&lt;/code&gt;이 주어지고, 각 자리수 중 두 개를 골라서 곱한 값중 가장 큰 수를 리턴하면 되는 문제이다.&lt;/p&gt;
&lt;p&gt;문제의 힌트에선 브루트 포스를 사용하라 했는데, 정렬하면 더 쉽게 풀 수 있다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;maxProduct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;digits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>TIL. Jul 24, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-24/</link><pubDate>Fri, 24 Jul 2026 21:23:17 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-24/</guid><description>&lt;h2 id="키워드"&gt;키워드&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;XOR 비트연산&lt;/li&gt;
&lt;li&gt;Observation&lt;/li&gt;
&lt;li&gt;블로그 스크립트 정리, git hook&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="내용"&gt;내용&lt;/h2&gt;
&lt;h3 id="xor-연산"&gt;XOR 연산&lt;/h3&gt;
&lt;p&gt;LeetCode에 어제에 이어서 XOR 연산 문제가 나왔다. 일반적인 사칙연산과 다른 특징들을 사용해야하는 문제들이었다. 가장 큰 특징은 비트 연산은 비트 수가 고정되어 있어서 연산의 결과가 엄청나게 많은 경우의 수를 만들지 않는다.&lt;/p&gt;
&lt;p&gt;예를 들어서, 곱셉의 경우에는 $10^3$ 미만의 두 수를 곱하면 최대 999 * 999 = 약 100만이 되어서 거의 7자리수의 경우의 수가 되는데, 비트연산은 더 이상 자리수의 확장이 일어나지 않는다.&lt;/p&gt;</description></item><item><title>SwiftUI. Discover Observation in SwiftUI - WWDC23</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-discover-observation-in-swiftui/</link><pubDate>Fri, 24 Jul 2026 17:41:15 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-discover-observation-in-swiftui/</guid><description>&lt;p&gt;SwiftUI의 Observation은 모델의 프로퍼티 변화를 추적하고, 그 변화에 맞춰 UI를 업데이트하는 기능이다. &lt;code&gt;@Observable&lt;/code&gt; 매크로를 사용하면 별도의 &lt;code&gt;ObservableObject&lt;/code&gt;, &lt;code&gt;@Published&lt;/code&gt;, &lt;code&gt;@ObservedObject&lt;/code&gt; 없이도 일반 Swift 타입에 가까운 형태로 관찰 가능한 모델을 만들 수 있다.&lt;/p&gt;
&lt;p&gt;핵심은 간단하다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;View가 읽은 프로퍼티가 바뀌면, 그 View가 다시 계산된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 글에서는 Observation의 동작 방식, &lt;code&gt;@State&lt;/code&gt;, &lt;code&gt;@Environment&lt;/code&gt;, &lt;code&gt;@Bindable&lt;/code&gt;을 언제 써야 하는지, 그리고 기존 &lt;code&gt;ObservableObject&lt;/code&gt; 기반 코드를 &lt;code&gt;@Observable&lt;/code&gt;로 옮기는 방법을 정리한다.&lt;/p&gt;
&lt;h2 id="observation"&gt;Observation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@Observable&lt;/code&gt;은 Swift 매크로다. 타입에 이 매크로를 붙이면 컴파일러가 해당 타입을 관찰할 수 있도록 코드를 확장한다.&lt;/p&gt;</description></item><item><title>Leetcode 3514. Number of Unique XOR Triplets II</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3514-number-of-unique-xor-triplets-ii/</link><pubDate>Fri, 24 Jul 2026 11:34:15 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3514-number-of-unique-xor-triplets-ii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/number-of-unique-xor-triplets-ii"&gt;https://leetcode.com/problems/number-of-unique-xor-triplets-ii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt; 길이의 배열 &lt;code&gt;nums&lt;/code&gt;가 주어지고, 여기에서 3개의 인덱스 &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt;를 (&lt;code&gt;i &amp;lt;= j &amp;lt;= k&lt;/code&gt;) 뽑아서 XOR 했을 때, 얻을 수 있는 모든 결과의 수를 리턴하는 문제이다.&lt;/p&gt;
&lt;p&gt;Leetcode 3513 문제와 다른 점은, &lt;code&gt;nums&lt;/code&gt;가 순열이 아니다. 따라서, 자연스럽게 모든 경우의 수를 커버하지 못한다. 다만, 인덱스 제약조건이 저번과 같으므로 &amp;lsquo;값 3개를 무작위&amp;rsquo;로 뽑는다는 점은 같다. 여전히 &lt;code&gt;n&lt;/code&gt;이 최대 1500이기 때문에, $O(n^3)$ 으로 풀기에는 무리가 있다.&lt;/p&gt;
&lt;p&gt;우선, 값의 중복을 가리지 않고, 인덱스도 가리지 않으므로 배열의 순서가 중요하지 않다. 따라서 배열에 있는 모든 중복을 제거하는 전처리를 한다.&lt;/p&gt;</description></item><item><title>Codeforces 492B. Vanya and Lanterns</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-492b-vanya-and-lanterns/</link><pubDate>Fri, 24 Jul 2026 02:34:52 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-492b-vanya-and-lanterns/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/contest/492/problem/B"&gt;https://codeforces.com/contest/492/problem/B&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;길의 길이 &lt;code&gt;l&lt;/code&gt;과 가로등의 위치 배열 &lt;code&gt;a&lt;/code&gt;가 주어지고, 모든 가로등이 길 전체를 비춰야 할때, 가로등 하나가 비추는 거리 &lt;code&gt;d&lt;/code&gt;를 출력하는 문제이다.&lt;/p&gt;
&lt;p&gt;문제 풀이는 단순하다. 가로등 사이의 간격을 계산하고, 그 간격을 모두 채울수만 있으면 된다.&lt;/p&gt;
&lt;p&gt;가로등이 길을 비추는 건 3가지 케이스로 생각해볼수 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;시작 가로등&lt;/li&gt;
&lt;li&gt;(양 옆에 가로등이 있는) 중간 가로등&lt;/li&gt;
&lt;li&gt;끝 가로동&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1번 3번 케이스가 엣지 케이스인데, 중간 가로등은 가로등 사이의 거리의 절반 만큼만 비추면 되지만, 시작 가로등과 끝 가로등은 시작점과 자신의 위치까지를 모두 스스로 비춰야 해서, 따로 처리해줘야 한다.&lt;/p&gt;</description></item><item><title>SwiftUI. The Swiftui Cookbook for Navigation - WWDC22</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-cookbook-for-navigation/</link><pubDate>Thu, 23 Jul 2026 22:36:54 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-cookbook-for-navigation/</guid><description>&lt;h2 id="the-swiftui-cookbook-for-navigation"&gt;The SwiftUI cookbook for navigation&lt;/h2&gt;
&lt;p&gt;SwiftUI의 새로운 내비게이션 API를 발표한 WWDC 세션을 정리했다. 이 내비게이션 API는 각각의 &lt;code&gt;NavigationLink&lt;/code&gt;가 관리하는 대신, 스택 전체의 상태를 데이터로 표현하고 직접 조작할 수 있게 만든다.&lt;/p&gt;
&lt;p&gt;이 구조를 사용하면 버튼을 눌러 이동하는 기본적인 내비게이션뿐만 아니라, 딥 링크나 특정 화면으로 바로 이동하기, 루트 화면으로 돌아가기, 현재 내비게이션 상태 저장까지 같은 모델로 처리할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New naviation API: 새로운 Data-driven 내비게이션 API&lt;/li&gt;
&lt;li&gt;Recipes for navigation: 탐색을 프로그래밍 방식으로 완전히 제어하기&lt;/li&gt;
&lt;li&gt;Persistent state: 새로운 API를 이용하여 앱의 내비게이션 상태를 유지하기&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class="callout" data-callout="note"&gt;
&lt;div class="callout__header"&gt;&lt;span class="callout__icon" aria-hidden="true"&gt;i&lt;/span&gt;&lt;span class="callout__title"&gt;갑자기 프로그래밍 방식?&lt;/span&gt;
&lt;/div&gt;
&lt;div class="callout__body"&gt;&lt;p&gt;SwiftUI는 처음부터 코드로 UI를 작성하는 프레임워크였기 때문에, 기존 &lt;code&gt;NavigationView&lt;/code&gt;도 &lt;code&gt;isActive&lt;/code&gt;나 &lt;code&gt;selection&lt;/code&gt;을 이용해 화면을 프로그래밍 방식으로 전환할 수 있었다.&lt;/p&gt;</description></item><item><title>Leetcode 3513. Number of Unique XOR Triplets I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3513-number-of-unique-xor-triplets-i/</link><pubDate>Thu, 23 Jul 2026 10:33:25 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3513-number-of-unique-xor-triplets-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/number-of-unique-xor-triplets-i"&gt;https://leetcode.com/problems/number-of-unique-xor-triplets-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;1에서 &lt;code&gt;n&lt;/code&gt;까지의 모든 값이 들어있는 &lt;code&gt;n&lt;/code&gt; 크기 배열 &lt;code&gt;nums&lt;/code&gt; 배열이 주어지고, 그 배열에서 인덱스 3개 &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt;, &lt;code&gt;k&lt;/code&gt; (&lt;code&gt;i &amp;lt;= j &amp;lt;= k&lt;/code&gt;)를 골라서 XOR 했을 때, 나올 수 있는 모든 값을 리턴하면 되는 문제이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nums&lt;/code&gt; 배열의 크기가 10만이고, 브루트 포스를하면 시간 복잡도가 $O(n^3)$ 이기 때문에 시간 내에 해결할 수 없다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;nums&lt;/code&gt;가 순열이라는 것과 XOR의 연산 특징을 알면 생각보다 간단한 공식으로 해결할 수 있다. 우선 인덱스 제약조건은 없는 것과 마찬가지인데, 등호를 포함한 대소관계이기 때문에, 인덱스를 중복해서 골라도 된다.&lt;/p&gt;</description></item><item><title>iOS. Demystify SwiftUI (3) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-3/</link><pubDate>Wed, 22 Jul 2026 23:13:56 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-3/</guid><description>&lt;h2 id="dependencies-swiftui는-무엇이-바뀌었는지-어떻게-알까"&gt;Dependencies: SwiftUI는 무엇이 바뀌었는지 어떻게 알까?&lt;/h2&gt;
&lt;p&gt;앞선 글에서는 SwiftUI가 View를 구분하는 방식인 Identity와, Identity가 유지되는 기간인 Lifetime을 정리했다. 이번에는 SwiftUI가 View를 업데이트하는 기준인 Dependencies를 살펴본다.&lt;/p&gt;
&lt;p&gt;먼저 결론부터 말하면 SwiftUI의 업데이트 과정은 다음과 같다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Dependency 변경
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;관련된 View 무효화
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;body 재평가
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;새로운 View Value와 이전 Value 비교
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;실제로 변경된 화면만 업데이트&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Identity는 같은 View인지 판단하고, Lifetime은 상태를 유지하며, Dependency는 어떤 View를 다시 계산해야 하는지 결정한다. 이 세 가지를 함께 이해하면 단순히 API 사용법을 외우는 것보다 SwiftUI의 동작을 더 잘 예측할 수 있다.&lt;/p&gt;</description></item><item><title>TIL. Jul 21, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-21/</link><pubDate>Tue, 21 Jul 2026 23:59:22 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-21/</guid><description>&lt;h2 id="키워드"&gt;키워드&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Codeforces 가입&lt;/li&gt;
&lt;li&gt;로컬 LLM opencode에 연결하고 ACP로 Xcode에 연동하기&lt;/li&gt;
&lt;li&gt;SwiftUI WWDC 세션, 특히 View Value와 View Identity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="내용"&gt;내용&lt;/h2&gt;
&lt;h3 id="ps-풀기-codeforces-가입"&gt;PS 풀기, Codeforces 가입&lt;/h3&gt;
&lt;p&gt;LeetCode에서만 문제를 푸는게 조금 시야가 좁아지나 싶어서, Codeforces에 가입했다. Swift 지원이 없지만, PS 문제를 풀 때 특정 언어에 종속되지 않으려고 꾸준히 Swift, Python, C++를 돌아가면서 풀고 있으니 큰 문제는 없다.&lt;/p&gt;
&lt;p&gt;가장 풀이 수가 많은 문제 하나를 풀었다. 매일 LeetCode 오늘의 문제를 푸는 것이 루틴 중 하나인데, Codeforces, 삼성 SW Expert Academy 등 온라인 저지 사이트 여럿 돌아다니면서 풀어보려 한다. BOJ가 사라진 이후로 LeetCode 의존이 꽤 심해졌는데, 다양하게 풀어봐야겠다.&lt;/p&gt;</description></item><item><title>SwiftUI. Demystify SwiftUI (2) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-2/</link><pubDate>Tue, 21 Jul 2026 21:42:49 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-2/</guid><description>&lt;h2 id="lifetime"&gt;Lifetime&lt;/h2&gt;
&lt;p&gt;1편에서는 SwiftUI가 View를 구분하는 방식인 Identity를 정리했다. 이번에는 Identity가 유지되는 시간인 Lifetime과, 그 안에서 &lt;code&gt;State&lt;/code&gt;가 어떻게 보존되는지 살펴본다.&lt;/p&gt;
&lt;p&gt;View Value는 계속 새로 만들어질 수 있지만, Identity가 유지되는 동안에는 같은 View의 Lifetime 안에 있다고 볼 수 있다. 그리고 &lt;code&gt;State&lt;/code&gt;와 &lt;code&gt;StateObject&lt;/code&gt;는 이 Lifetime에 연결되어 있기 때문에 Identity가 바뀌면 함께 교체된다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-2/image-001-optimized-image.webp"&gt;&lt;p&gt;고양이가 하루 동안 이곳저곳 움직이더라도 우리는 계속 같은 고양이라고 생각한다. 이처럼 Identity는 시간에 따라 달라지는 여러 값을 하나의 안정적인 존재로 연결한다. 시간의 흐름 속에서 연속성을 만들어 주는 셈이다.&lt;/p&gt;</description></item><item><title>DevOps. 로컬 LLM 모델 설치하고 UI 붙여보기</title><link>https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-1/</link><pubDate>Tue, 21 Jul 2026 10:34:39 +0900</pubDate><guid>https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-1/</guid><description>&lt;p&gt;Codex는 iOS 개발할 때만 사용하고, 다른 작업은 주로 무료 모델로 처리했다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dev-data-server-light&lt;/code&gt;를 개발할 때는 Cursor를 사용했는데, 개발 도중 사용량이 모두 소진돼 Antigravity로 옮겨야 했다.&lt;/p&gt;
&lt;p&gt;그래서 로컬에서 직접 실행하는 LLM 환경을 찾았고, 생각보다는 쉽게 환경을 구축할 수 있었다., 맥미니에서 만족스럽게 사용하고 있다. 이번 글에서는 맥북 에어에도 같은 환경을 설치한 과정을 정리한다.&lt;/p&gt;
&lt;h2 id="맥북-에어-사양"&gt;맥북 에어 사양&lt;/h2&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-1/image-001-optimized-image.webp#center" width="360"&gt;&lt;h2 id="설치"&gt;설치&lt;/h2&gt;
&lt;h3 id="ollama-설치하고-서버-켜기"&gt;ollama 설치하고 서버 켜기&lt;/h3&gt;
&lt;p&gt;맥에서는 Homebrew로 쉽게 설치할 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-zsh" data-lang="zsh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;brew install ollama&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/devops-llm-building-a-local-llm-1/image-002-optimized-image.webp"&gt;&lt;p&gt;설치가 끝났으면 Ollama 서버를 켜야 한다. Ollama는 단순히 실행하는 앱이 아니라, 서버 형태로 동작한다.&lt;/p&gt;</description></item><item><title>LeetCode 3499. Maximize Active Section With Trade I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3499-maximize-active-section-with-trade-i/</link><pubDate>Tue, 21 Jul 2026 10:29:30 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3499-maximize-active-section-with-trade-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/maximize-active-section-with-trade-i"&gt;https://leetcode.com/problems/maximize-active-section-with-trade-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;'0'&lt;/code&gt;와 &lt;code&gt;'1'&lt;/code&gt;로만 이루어진 문자열 &lt;code&gt;s&lt;/code&gt;가 존재하고, 문제에서 주어진 연산을 최대 1번 적용하여 문자열에 있는 &lt;code&gt;'1'&lt;/code&gt;의 개수를 최대로 만든 뒤 그 개수를 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;주어진 연산은 다음과 같다. (순서대로 둘 다 적용해야 한다.)&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;양 옆이 &lt;code&gt;'0'&lt;/code&gt;로 둘러싸인 연속된 &lt;code&gt;'1'&lt;/code&gt; 블록 하나를 선택해서 모두 &lt;code&gt;'0'&lt;/code&gt;로 바꾼다.&lt;/li&gt;
&lt;li&gt;양 옆이 &lt;code&gt;'1'&lt;/code&gt;으로 둘러싸인 연속된 &lt;code&gt;'0'&lt;/code&gt; 블록 하나를 선택해서 모두 &lt;code&gt;'1'&lt;/code&gt;으로 바꾼다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;문제에서 &lt;code&gt;s&lt;/code&gt;의 양 옆에 &lt;code&gt;'1'&lt;/code&gt;을 붙이라 했는데, 이때 추가된 &lt;code&gt;'1'&lt;/code&gt;은 최종 반환값에 포함되지 않는다.&lt;/p&gt;</description></item><item><title>Codeforces 1A. Theatre Square</title><link>https://kelly-chui.github.io/ps/2026/ps-codeforces-1a-theatre-square/</link><pubDate>Tue, 21 Jul 2026 10:28:57 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-codeforces-1a-theatre-square/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://codeforces.com/problemset/problem/1/A"&gt;https://codeforces.com/problemset/problem/1/A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;Codeforces에서 푼 첫 문제.&lt;/p&gt;
&lt;p&gt;$n \times m$ 크기의 직사각형 도시가 있고, 그 도시를 $a \times a$ 크기의 타일로 뒤덮는 문제이다. 타일은 도시 경계를 넘어가도 되지만, 잘라선 안되고 겹쳐도 안된다. 즉, 필요한 타일의 개수는 가로/세로 각각을 $a$로 나눈 값을 올림하여 곱하면 된다.&lt;/p&gt;
&lt;p&gt;문제에 간단한 함정이 하나 있는데, &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt;, &lt;code&gt;a&lt;/code&gt;의 범위가 최대 $10^9$이라 곱셈 결과가 &lt;code&gt;int&lt;/code&gt; 범위를 넘어갈 수 있으므로 &lt;code&gt;long long&lt;/code&gt;을 사용을 사용해야 한다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cmath&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>TIL. Jul 20, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-20/</link><pubDate>Mon, 20 Jul 2026 22:18:49 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-20/</guid><description>&lt;h2 id="키워드"&gt;키워드&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;단조 스택&lt;/li&gt;
&lt;li&gt;Hugo Flat Post -&amp;gt; Page Bundle&lt;/li&gt;
&lt;li&gt;블로그 스크립트는 어떤 언어로?&lt;/li&gt;
&lt;li&gt;Xcode 프로젝트명 바꾸기&lt;/li&gt;
&lt;li&gt;SwiftUI Identity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="내용"&gt;내용&lt;/h2&gt;
&lt;h3 id="leetcode-1081-substring-subsequence-monotonic-stack"&gt;LeetCode 1081, Substring, Subsequence, Monotonic Stack&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://kelly-chui.github.io/ps/2026/ps-leetcode-1081-smallest-subsequence-of-distinct-characters/"&gt;LeetCode 1081&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PS 문제를 풀면서, 처음에 Medium 문제인데 좀 해맸다, LCS 두 개를 하면서 Substring이랑 Subsequence 차이를 분명히 알았는데, Substring으로 생각하고 풀어서 스택을 써야 할 곳에 투 포인터를 썼다.&lt;/p&gt;
&lt;p&gt;단조 스택(Monotonic Stack) 문제인데, 사실 이런 스택이 있는지 오늘 처음 알았다. 그냥 스택은 스택으로 생각했으니까, 마치 Binary Search와 Parametric Search같은 느낌인가.&lt;/p&gt;</description></item><item><title>SwiftUI. Demystify SwiftUI (1) - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-1/</link><pubDate>Mon, 20 Jul 2026 21:51:21 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-demystify-swiftui-1/</guid><description>&lt;aside class="callout" data-callout="note"&gt;
&lt;div class="callout__header"&gt;&lt;span class="callout__icon" aria-hidden="true"&gt;i&lt;/span&gt;&lt;span class="callout__title"&gt;시작하기 전에&lt;/span&gt;
&lt;/div&gt;
&lt;div class="callout__body"&gt;&lt;p&gt;Identity는 화면에 띄워지는 UI 요소들이 같은 요소인지, 다른 요소인지 구분하는 방식이다.&lt;/p&gt;
&lt;p&gt;이 WWDC 세션에서 가장 중요한건, View 프로토콜을 채택하여 작성하는 View Structure가 실제 화면에 보이는 요소가 아니라 그냥 그 요소의 설계도일 뿐이라는 것이다. (UIKit과 많이 다르다)&lt;/p&gt;
&lt;p&gt;Swift에서 &amp;lsquo;Value Type은 Immutablity를 가진다.&amp;rsquo; 이라는 말이 가장 크게 체감되는 부분이기도 한데, SwiftUI에서 코드로 작성한 View도 Value Type이고 당연히 Immutable하다. 따라서 한 번 생성된 값은 변하지 않아야 한다. 만약 내부의 값이 변해야 하면 UIKit의 View Controller 처럼 은근슬쩍 내부 프로퍼티만 바꾸지 않고, Value 전체를 새로 만든다.&lt;/p&gt;</description></item><item><title>LeetCode 1081. Smallest Subsequence of Distinct Characters</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1081-smallest-subsequence-of-distinct-characters/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1081-smallest-subsequence-of-distinct-characters/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/smallest-subsequence-of-distinct-characters"&gt;https://leetcode.com/problems/smallest-subsequence-of-distinct-characters&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문자열 &lt;code&gt;s&lt;/code&gt;에 있는 모든 개별 문자를 정확히 한 번씩 포함하는 부분수열 중, 사전순으로 가장 작은 것을 리턴하면 된다.&lt;/p&gt;
&lt;p&gt;처음에 투 포인터를 생각했는데, 원소가 굳이 쭉 이어질 필요가 없으니 스택을 활용했다. 처음에 전처리로 각 문자의 마지막 등장 인덱스를 구해둔다.&lt;/p&gt;
&lt;p&gt;스택 top의 마지막 인덱스가 현재 인덱스보다 크면 뒤에 또 나온다는 뜻이므로 제거할 수 있다. 스택에 문자를 추가하기 전, 아래 세 조건을 모두 만족할 때 top을 pop하면 된다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;스택이 비어있지 않다&lt;/li&gt;
&lt;li&gt;스택 top이 현재 문자보다 크다 (사전순으로 뒤에 있다)&lt;/li&gt;
&lt;li&gt;스택 top 문자가 뒤에 또 등장한다 (&lt;code&gt;lastIndice[stack[-1]] &amp;gt; idx&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;smallestSubsequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lastIndice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lastIndice&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;lastIndice&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>LeetCode 1260. Shift 2D Grid</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1260-shift-2d-grid/</link><pubDate>Mon, 20 Jul 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1260-shift-2d-grid/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/shift-2d-grid"&gt;https://leetcode.com/problems/shift-2d-grid&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;$m \times n$ 2d 그리드에 있는 원소들을 오른쪽으로 &lt;code&gt;k&lt;/code&gt;번 민 결과를 리턴하면 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grid[row][n - 1]&lt;/code&gt; → &lt;code&gt;grid[row + 1][0]&lt;/code&gt; : 마지막 열의 원소는 다음 행의 첫 번째 열로 이동&lt;/li&gt;
&lt;li&gt;&lt;code&gt;grid[m - 1][n - 1]&lt;/code&gt; → &lt;code&gt;grid[0][0]&lt;/code&gt; : 마지막 행의 마지막 열 원소는 첫 번째 행의 첫 번째 열로 이동&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;k&lt;/code&gt;번 직접 반복하는 대신, 그리드를 1차원으로 평탄화하면 shift 연산이 단순한 배열 회전으로 바뀐다.&lt;/p&gt;
&lt;p&gt;평탄화한 배열을 오른쪽으로 &lt;code&gt;k&lt;/code&gt;칸 회전시킨 뒤, 다시 $m \times n$ 2차원 배열로 복원하면 된다.
단, &lt;code&gt;k&lt;/code&gt;가 배열 길이 $m \times n$ 보다 클 수 있으므로 모듈러 연산으로 정규화한다.&lt;/p&gt;</description></item><item><title>Leetcode 3867. Sum of GCD of Formed Pairs</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3867-sum-of-gcd-of-formed-pairs/</link><pubDate>Thu, 16 Jul 2026 10:29:15 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3867-sum-of-gcd-of-formed-pairs/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/sum-of-gcd-of-formed-pairs"&gt;https://leetcode.com/problems/sum-of-gcd-of-formed-pairs&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제에서 지시한 내용을 그대로 구현하면 되는 문제다. 문제의 지시사항은 다음과 같다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;인티저 배열 &lt;code&gt;nums&lt;/code&gt;의 누적 최대값 배열 &lt;code&gt;mx&lt;/code&gt;를 만든다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefixGcd[i] = gcd(nums[i], mx[i])&lt;/code&gt; 으로 이루어진 배열을 만든다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefixGcd&lt;/code&gt;를 오름차순 정렬한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;prefixGcd&lt;/code&gt;의 제일 큰 값과 제일 작은 값의 쌍을 만들어, GCD를 구하는 것을 더 이상 만들지 못할 때 까지 반복한다. 만약 &lt;code&gt;prefixGcd&lt;/code&gt;의 원소의 개수가 홀수라서 페어을 만들지 못한 하나가 남는다면 무시한다.&lt;/li&gt;
&lt;li&gt;&amp;lsquo;4&amp;rsquo;에서 구한 모든 GCD 값의 합을 리턴한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;페어을 만드는건 간단한 형태의 투 포인터로 해결했다. 정렬과 유클리드 호제법을 제외하곤 모두 $O(n)$에 해결되기 때문에, 시간복잡도는 $O(n \log n + n \log V) = O(n \log (nV))$이다.&lt;/p&gt;</description></item><item><title>Leetcode 3658. GCD of Odd and Even Sums</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3658-gcd-of-odd-and-even-sums/</link><pubDate>Wed, 15 Jul 2026 10:32:37 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3658-gcd-of-odd-and-even-sums/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/gcd-of-odd-and-even-sums"&gt;https://leetcode.com/problems/gcd-of-odd-and-even-sums&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;인티저 &lt;code&gt;n&lt;/code&gt;이 하나 주어지고 작은 짝수 &lt;code&gt;n&lt;/code&gt;개, 가장 홀수 &lt;code&gt;n&lt;/code&gt;개를 각각 모두 더한 합 간의 GCD를 구하는 문제이다.&lt;/p&gt;
&lt;p&gt;문제에서 요구하는 내용이 너무 간단해서, &lt;code&gt;gcd()&lt;/code&gt;를 쓰지 않고, 유클리드 호제법을 직접 작성해서 GCD를 구했다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;gcdOfOddEvenSums&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sumOdd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sumEven&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sumEven&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sumOdd&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sumEven&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sumOdd&lt;/span&gt; &lt;span class="o"&gt;%=&lt;/span&gt; &lt;span class="n"&gt;sumEven&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sumOdd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sumEven&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sumOdd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Leetcode 3336. Find the Number of Subsequences With Equal GCD</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3336-find-the-number-of-subsequences-with-equal-gcd/</link><pubDate>Tue, 14 Jul 2026 09:28:12 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3336-find-the-number-of-subsequences-with-equal-gcd/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-the-number-of-subsequences-with-equal-gcd"&gt;https://leetcode.com/problems/find-the-number-of-subsequences-with-equal-gcd&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;수열 &lt;code&gt;nums&lt;/code&gt;이 주어지고, &lt;code&gt;nums&lt;/code&gt;에서 서로 원소가 겹치지 않게 부분 수열을 두 개 만든 뒤, 각 부분 수열(이하 A, B라 함)의 GCD가 같은 경우의 수를 찾는 문제이다.&lt;/p&gt;
&lt;p&gt;만약 브루트 포스를 시도한다면, 원소의 개수 &lt;code&gt;n&lt;/code&gt;, 각 원소가 가질 수 있는 상태가 3개(부분 수열 A, 부분 수열 B, 아예 미포함)이므로, 시간 복잡도가 $O(n \times 3^n)$ 이 되는데, &lt;code&gt;nums&lt;/code&gt;의 최대 크기가 200이므로 유효한 시간 내에 해결할 수 없다.&lt;/p&gt;
&lt;p&gt;하지만 부분 수열을 점점 채워나가면서 두 부분 수열을 비교할 수 있으므로, DP를 사용하면 O(n * 부분 수열A의 최대 gcd * 부분 수열B의 gcd 최대값)이 된다. 문제의 제약조건에서 원소의 최대 크기는 200이고, GCD는 원소보다 클 수 없으므로, $O(n \times 200 \times 200)$으로 줄일 수 있다.&lt;/p&gt;</description></item><item><title>Leetcode 1331. Rank Transform of an Array</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1331-rank-transform-of-an-array/</link><pubDate>Mon, 13 Jul 2026 11:09:28 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1331-rank-transform-of-an-array/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/rank-transform-of-an-array"&gt;https://leetcode.com/problems/rank-transform-of-an-array&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;배열의 각 원소를 크기 기준으로 순위로 변환해 리턴하는 문제이다. 배열을 정렬한 뒤 각 원소에 순위를 매핑하고, 원본 배열 순서대로 순위를 꺼내 리턴한다.&lt;/p&gt;
&lt;p&gt;문제에서 주의점이 하나 있는데, 같은 숫자는 같은 순위를 가진다는 것이다. 따라서 매핑할 때, 중복처리를 해줘야 한다.&lt;/p&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;arrayRankTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sortedArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rankDict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sortedArr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rankDict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rankDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rankDict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Leetcode 1291. Sequential Digits</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1291-sequential-digits/</link><pubDate>Mon, 13 Jul 2026 10:59:57 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1291-sequential-digits/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/sequential-digits"&gt;https://leetcode.com/problems/sequential-digits&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;low&lt;/code&gt;와 &lt;code&gt;high&lt;/code&gt; 사이의 수 중, 각 자릿수가 123, 3456 처럼 연속으로 이어지는 수를 모두 리턴하는 문제이다&lt;/p&gt;
&lt;p&gt;문제와 제약조건을 보고 바로 DFS 백트래킹로 풀어야겠다는 생각을 했다. 구간의 크기가 최대 1억이기 때문에, 하나하나 확인하는 것은 무리가 있다. 따라서 수를 하나씩 붙여나가면서 확인하고, 조건에 벗어나면 프룬닝 하면 되는 전형적인 문제로 생각했다.&lt;/p&gt;
&lt;p&gt;백트래킹으로도 충분히 빠른 속도로 문제를 풀 수 있지만, 문제를 제출하고 난 뒤 효율성을 검증해보니. &lt;code&gt;high&lt;/code&gt; 크기가 최대 1억이기 때문에, 후보들의 수가 몇개 되지 않기 때문에, 실제로 자리수가 연속되는 모든 숫자들을 만들고 확인하는 방식이 더 빠를수도 있다고 한다.&lt;/p&gt;</description></item><item><title>TIL. Jul 13, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-13/</link><pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-13/</guid><description>&lt;h2 id="키워드"&gt;키워드&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Python 로컬 변수 스코프.&lt;/li&gt;
&lt;li&gt;Python에서 람다식 정리, Swift 인라인 클로저와 다른점.&lt;/li&gt;
&lt;li&gt;블로그 마이그레이션 하면서 이전에 썼던 iOS 관련 글 복습&lt;/li&gt;
&lt;li&gt;블로그에서 카테고리를 몇개를 해야하는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="내용"&gt;내용&lt;/h2&gt;
&lt;h3 id="python-로컬-변수-스코프-문제"&gt;Python 로컬 변수 스코프 문제&lt;/h3&gt;
&lt;p&gt;Leetcode 1291번 문제를 푸는 도중에 다음과 같이 코드를 작성했다. 로직에 오류가 있어서 통과는 못하는 코드다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sequentialDigits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;intSeq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;intSeq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="c1"&gt;# 이부분&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;seq&lt;/code&gt; 변수가 &lt;code&gt;sequentialDigits&lt;/code&gt; 함수의 로컬 변수인데, &lt;code&gt;if&lt;/code&gt; 문 안의 &lt;code&gt;seq = []&lt;/code&gt; 부분 때문에 에러가 났다.&lt;/p&gt;</description></item><item><title>TIL. Jul 12, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-12/</link><pubDate>Sun, 12 Jul 2026 21:21:18 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-12/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Hugo 블로그에서 Mermaid를 외부 CDN 없이 렌더링하도록 변경&lt;/li&gt;
&lt;li&gt;Mermaid가 필요한 페이지에서만 스크립트를 로드하도록 최적화&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hugo --minify&lt;/code&gt;로 빌드 검증&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;Mermaid 코드 블록은 &lt;code&gt;layouts/_markup/render-codeblock-mermaid.html&lt;/code&gt;에서 &lt;code&gt;&amp;lt;pre class=&amp;quot;mermaid&amp;quot;&amp;gt;&lt;/code&gt;로 변환하고, &lt;code&gt;layouts/_partials/extend_footer.html&lt;/code&gt;에서 Mermaid가 포함된 페이지에만 스크립트를 삽입하도록 구성했다.&lt;/p&gt;
&lt;p&gt;처음에는 ESM 파일 하나만 &lt;code&gt;static/&lt;/code&gt;에 복사했지만, 해당 파일이 내부 chunk를 추가로 참조하는 구조라 렌더링이 깨졌다. 브라우저가 다이어그램을 SVG로 바꾸지 못하고 원문 텍스트처럼 보여서, 의존성이 단순한 &lt;code&gt;mermaid.min.js&lt;/code&gt;로 교체했다.&lt;/p&gt;
&lt;p&gt;외부 CDN을 제거하는 작업도 단순히 파일을 내려받는 것으로 끝나지 않았다. 번들 파일의 의존성과 실행 방식까지 확인해야 실제 정적 사이트에서 안정적으로 동작한다는 것을 배웠다.&lt;/p&gt;</description></item><item><title>Leetcode 3532. Path Existence Queries in a Graph I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3532-path-existence-queries-in-a-graph-i/</link><pubDate>Thu, 09 Jul 2026 09:21:23 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3532-path-existence-queries-in-a-graph-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/path-existence-queries-in-a-graph-i"&gt;https://leetcode.com/problems/path-existence-queries-in-a-graph-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;그래프 각 노드의 연결 조건이 주어지고, 들어오는 쿼리들에 있는 두 노드들이 연결되어있는지 확인하는 문제이다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;queries&lt;/code&gt; 배열의 길이가 최대 10만이므로, BFS를 이용해서 풀기는 거의 불가능하다. BFS보다 더 빠르게 &amp;lsquo;연결 여부만&amp;rsquo; 확인하는 방법은 Union-Find Set을 사용하면 된다.&lt;/p&gt;
&lt;p&gt;우선 연결 조건은 두 노드의 절대 차이(노드 번호의 차이의 절대값)가 &lt;code&gt;maxDiff&lt;/code&gt; 이하여야 하는데, 문제에서 &lt;code&gt;nums&lt;/code&gt; 배열이 오름차순으로 정렬되어 있다고 했으므로, &lt;code&gt;nums[j] - nums[i] &amp;lt;= maxDiff&lt;/code&gt; 를 만족하는 연속된 범위를 투 포인터로 찾을 수 있다.&lt;/p&gt;</description></item><item><title>Leetcode 3020. Find the Maximum Number of Elements in Subset</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3020-find-the-maximum-number-of-elements-in-subset/</link><pubDate>Thu, 09 Jul 2026 08:23:02 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3020-find-the-maximum-number-of-elements-in-subset/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/"&gt;https://leetcode.com/problems/find-the-maximum-number-of-elements-in-subset/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;주어진 배열의 원소들로 만들 수 있는 가장 긴 &lt;code&gt;[x, x², x⁴, ..., x^(2^k), ..., x⁴, x², x]&lt;/code&gt; 형태의 부분집합 길이를 반환하는 문제다. 이하에서는 이 형태를 피라미드라고 부른다.&lt;/p&gt;
&lt;p&gt;어떤 문제든 제약 조건이 중요하지만, 이 문제는 특히 제약 조건이 중요하다. 주어진 꼴에서 원소들은 급격히 증가하는데, &lt;code&gt;1 &amp;lt;= nums[i] &amp;lt;= 10^9&lt;/code&gt; 라는 제약 조건이 있기에, 배열의 최대 크기를 예상할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x&lt;/code&gt;가 1일 때는 몇 번을 제곱해도 1이므로, &lt;code&gt;nums&lt;/code&gt; 배열 내부에 있는 1의 개수에 따라 달려있다. 피라미드 꼴은 항상 홀수이므로, 1의 개수가 홀수일때는 그대로, 짝수일때는 1을 뺀 값을 문제에서 요구하는 최대값의 초기 값으로 정한다.&lt;/p&gt;</description></item><item><title>LeetCode 3756. Concatenate Non-Zero Digits and Multiply by Sum II</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3756-concatenate-non-zero-digits-and-multiply-by-sum-ii/</link><pubDate>Wed, 08 Jul 2026 14:30:01 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3756-concatenate-non-zero-digits-and-multiply-by-sum-ii/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/concatenate-non-zero-digits-and-multiply-by-sum-ii"&gt;https://leetcode.com/problems/concatenate-non-zero-digits-and-multiply-by-sum-ii&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;1번 문제와 로직은 동일하다. 차이점은 스트링 &lt;code&gt;s&lt;/code&gt;의 서브스트링에 같은 작업을 &lt;code&gt;queries&lt;/code&gt;마다 반복해야 한다는 점이다.
&lt;code&gt;queries&lt;/code&gt;의 원소가 최대 10만 개이므로, 매 쿼리마다 부분 문자열을 슬라이싱해서 처리하면 시간 초과가 난다. 따라서 전처리를 통해 각 쿼리를 $O(1)$ 혹은 $O(n \log n)$에 처리할 수 있도록 해야 한다.&lt;/p&gt;
&lt;p&gt;전처리 단계에서 네 가지 누적 배열을 만든다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pow10&lt;/code&gt;: $\text{pow10}[i] = 10^i \mod (10^9 + 7)$&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preSum&lt;/code&gt;: 각 인덱스까지 자릿수의 합&lt;/li&gt;
&lt;li&gt;&lt;code&gt;preConcat&lt;/code&gt;: 각 인덱스까지 0이 아닌 숫자들을 이어붙인 값&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nonZeroCount&lt;/code&gt;: 각 인덱스까지 0이 아닌 숫자의 개수&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쿼리 &lt;code&gt;[l, r]&lt;/code&gt;이 들어오면 네 배열로 &lt;code&gt;x&lt;/code&gt;와 &lt;code&gt;sum&lt;/code&gt;을 $O(1)$에 구해 $x \times \text{sum} \mod (10^9 + 7)$를 리턴한다. 0이 아닌 숫자가 없는 경우는 수식이 자연스럽게 $0$을 리턴하게 된다.&lt;/p&gt;</description></item><item><title>LeetCode 3754. Concatenate Non-Zero Digits and Multiply by Sum I</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-3754-concatenate-non-zero-digits-and-multiply-by-sum-i/</link><pubDate>Tue, 07 Jul 2026 14:30:01 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-3754-concatenate-non-zero-digits-and-multiply-by-sum-i/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/concatenate-non-zero-digits-and-multiply-by-sum-i"&gt;https://leetcode.com/problems/concatenate-non-zero-digits-and-multiply-by-sum-i&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제에서 주어진 조건에 따라서 스트링을 조작하면 되는 간단한 문제이다. 인티저에서 스트링으로, 스트링에서 인티저로 타입 컨버전만 조심하면된다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;주어진 정수 n을 스트링으로 변환한 다음, 앞에서부터 순회하여 &lt;code&gt;&amp;quot;0&amp;quot;&lt;/code&gt;을 제거한 스트링 &lt;code&gt;filtered&lt;/code&gt;를 만든다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filered&lt;/code&gt;를 인티저로 타입 컨버전 해서 &lt;code&gt;x&lt;/code&gt;를 구한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;filered&lt;/code&gt;의 각 원소를 인티저로 컨버전 한 다음, 합을 구해서 &lt;code&gt;sum&lt;/code&gt;을 구한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x * sum&lt;/code&gt;을 리턴한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="코드"&gt;코드&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sumAndMultiply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>LeetCode 1288. Remove Covered Intervals</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1288-remove-covered-intervals/</link><pubDate>Mon, 06 Jul 2026 12:33:49 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1288-remove-covered-intervals/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/remove-covered-intervals"&gt;https://leetcode.com/problems/remove-covered-intervals&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;여러 개의 구간이 주어지고, 다른 구간에 완전히 포함되는 구간을 제거한 이후, 남은 구간의 개수를 리턴하면 되는 문제이다.&lt;/p&gt;
&lt;p&gt;가장 쉬운 방법은 브루트 포스이다. 구간의 개수가 최대 1000개이기 때문에, O(n^2) 방식을 사용해도 충분히 통과 가능하다.&lt;/p&gt;
&lt;p&gt;하지만 정렬을 이용하면 쉽게 O(n * log(n)) 으로 풀 수 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;구간 시작 부분을 기준으로 오름차순 정렬한다. 시작 부분이 같은 경우엔 끝 부분을 기준으로 내림차순 정렬한다.&lt;/li&gt;
&lt;li&gt;정렬된 배열을 앞에서부터 순회하며, 지금까지 등장한 끝 부분의 최대값(maxEnd)을 추적한다.&lt;/li&gt;
&lt;li&gt;현재 구간의 끝이 maxEnd보다 크면, 이전 어떤 구간에도 포함되지 않는 새로운 구간이므로 카운트하고 maxEnd를 갱신한다.&lt;/li&gt;
&lt;li&gt;현재 구간의 끝이 maxEnd보다 작거나 같으면, 이전 구간에 완전히 포함되는 구간이므로 제거한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1번에서 시작 부분 기준으로 정렬했기 때문에, 시작 조건은 자동으로 만족되어 끝 부분만 비교하면 충분하다.&lt;/p&gt;</description></item><item><title>LeetCode 1301. Number of Paths with Max Score</title><link>https://kelly-chui.github.io/ps/2026/ps-leetcode-1301-number-of-paths-with-max-score/</link><pubDate>Sun, 05 Jul 2026 14:30:01 +0900</pubDate><guid>https://kelly-chui.github.io/ps/2026/ps-leetcode-1301-number-of-paths-with-max-score/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/number-of-paths-with-max-score"&gt;https://leetcode.com/problems/number-of-paths-with-max-score&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;2차원 그리드의 우하단에서 시작해 좌상단까지 이동하면서, 경로에 있는 숫자들의 합의 최대값과 그 최대값이 나오는 경로의 개수를 구하는 문제이다.&lt;/p&gt;
&lt;p&gt;최단 거리를 찾는 문제가 아니므로 BFS나 Dijkstra는 필요 없고, 어떻게 경로의 수를 구할지가 핵심이다. 이동 방향은 문제에서 주어져 있으므로, 각 노드에서 인접한 노드들의 값을 활용해 특정 합(&lt;code&gt;v&lt;/code&gt;)에 도달하는 경로의 개수를 구할 수 있다.&lt;/p&gt;
&lt;p&gt;이런 문제를 효율적으로 푸는 방법은 결국 DP이다. 처음에 점화식을 이렇게 만들었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dp[r][c][v]: row = r, column = c인 노드에서 지나온 경로에 있는 칸들의 합이 v가 되는 경로의 개수.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;테스트 케이스는 통과할 수 있었지만, 실제 제출했을 때는 시간 초과가 되어서 통과하지 못했다. &lt;code&gt;v&lt;/code&gt; 차원 때문에 dp공간이 너무 커지는 것이 문제였다.&lt;/p&gt;</description></item><item><title>TIL. Jul 2, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-07-02/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-07-02/</guid><description>&lt;h1 id="요약"&gt;요약&lt;/h1&gt;
&lt;p&gt;오늘은 0-1 BFS를 문제에 적용해 보면서 알고리즘 선택의 중요성을 느꼈다. 또한 티스토리 블로그를 Hugo로 이전하기 위한 마이그레이션 스크립트를 작성하며 HTML을 Markdown으로 변환했다.&lt;/p&gt;
&lt;h2 id="배운-것"&gt;배운 것&lt;/h2&gt;
&lt;h3 id="0-1-bfs"&gt;0-1 BFS&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;LeetCode 3286. Find a Safe Walk Through a Grid&lt;/li&gt;
&lt;li&gt;사용 언어: Python, Swift&lt;/li&gt;
&lt;li&gt;사용 알고리즘: Dijkstra, 0-1 BFS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그동안은 거리 개념이 나오면 무조건 다익스트라를 사용했는데, 처음으로 0-1 BFS를 이용해서 문제를 풀었다. 같은 문제를 Python에서는 다익스트라로 풀었고. 0-1 BFS는 Swift로 풀었다.&lt;br&gt;
기존에 Swift에서 BFS를 사용할 때는 배열과 인덱스 포인터를 이용한 유사 Queue를 사용했는데, 이 방식으로는 큐의 헤드에 원소를 push하는 메소드를 구현하기 어려워서 배열을 사용했다. 문제의 제약조건이 널널해서 배열로 충분히 통과했는데, 어떻게 해야할지는 고민해봐야 할 것 같다. Linked List를 이용해서 큐를 만들면 되지만, 이게 힙와 다익스트라를 쓰는 것보다 코드를 작성하는 입장에서 효율적일지는 잘 모르겠다.&lt;/p&gt;</description></item><item><title>Archive. System Programming 정리 노트</title><link>https://kelly-chui.github.io/posts/archive-system-programming/</link><pubDate>Mon, 29 Jun 2026 16:38:00 +0900</pubDate><guid>https://kelly-chui.github.io/posts/archive-system-programming/</guid><description>&lt;p&gt;학부연구원 시절 FPGA랑 임베디드 살짝 하면서 적어놨던 노트를 최근 클라우드 정리할 때 발견해서, 간단하게 블로그에 포스팅함.&lt;/p&gt;
&lt;h2 id="rtos"&gt;RTOS&lt;/h2&gt;
&lt;p&gt;RTOS(Real-Time Operating System)는 정해진 시간 안에 작업을 수행하는 것을 보장하도록 설계된 운영체제이다.&lt;/p&gt;
&lt;p&gt;일반적인 운영체제와 다르게 RTOS는 작업이 정해진 시간 내에 반드시 수행되는 예측 가능성을 가장 중요하게 생각한다. 산업용 장비, 자동차, 드론, 의료기기와 같은 임베디드 시스템에서 주로 사용된다.&lt;/p&gt;
&lt;h2 id="uart"&gt;UART&lt;/h2&gt;
&lt;p&gt;UART(Universal Asynchronous Receiver/Transmitter)는 가장 널리 사용되는 직렬 통신 방식 중 하나이다.&lt;/p&gt;
&lt;p&gt;구조가 단순하고 구현이 쉬워 디버깅 콘솔, 센서, 마이크로컨트롤러 간 통신 등에 자주 사용된다. 다만 송신과 수신 장치가 동일한 통신 속도(Baud Rate)를 사용해야 한다.&lt;/p&gt;</description></item><item><title>TIL. Jun 19, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-19/</link><pubDate>Fri, 19 Jun 2026 20:06:46 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-19/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;AGENTS.override.md&lt;/code&gt;의 적용 순서 정리&lt;/li&gt;
&lt;li&gt;전역 규칙과 프로젝트 규칙이 어떻게 병합되는지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;규칙 파일은 전역에서 프로젝트 하위 디렉토리로 내려오면서 적용된다. 같은 디렉토리에서는 &lt;code&gt;AGENTS.override.md&lt;/code&gt;가 &lt;code&gt;AGENTS.md&lt;/code&gt;보다 우선하고, 하위 디렉토리의 규칙이 더 구체적인 지침으로 해석된다.&lt;/p&gt;
&lt;p&gt;결국 규칙은 전역에서 프로젝트 루트, 현재 작업 디렉토리 순서로 합쳐진다. 공통 원칙은 위쪽에 두고, 특정 모듈의 세부 규칙은 아래쪽에 두는 이유가 여기에 있다.&lt;/p&gt;
&lt;h2 id="해결-내용"&gt;해결 내용&lt;/h2&gt;
&lt;p&gt;전역 원칙은 전역 규칙에, 프로젝트 공통 원칙은 루트에, 모듈별 세부 지침은 하위 디렉토리에 두는 계층을 정리했다. 더 가까운 디렉토리의 규칙이 구체적인 지침으로 적용된다는 점도 확인했다.&lt;/p&gt;</description></item><item><title>TIL. Jun 17, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-17/</link><pubDate>Wed, 17 Jun 2026 21:52:31 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-17/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Antigravity의 Rules, Skills, Workflows 구조 정리&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dev-data-server-light&lt;/code&gt;의 AGENTS 규칙을 새 구조에 맞춰 마이그레이션&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;Antigravity의 핵심 구조는 다음처럼 정리할 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Rules = 행동 규칙
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Skills = 특정 분야의 지식과 노하우
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Workflows = 작업 절차&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Rules는 항상 지켜야 할 원칙을 정의하고, Skills는 Storage 설계나 코드 리뷰처럼 특정 작업에 필요한 전문 지식을 담는다. Workflows는 계획, 구현, 테스트처럼 작업을 어떤 순서로 진행할지 정의한다.&lt;/p&gt;
&lt;p&gt;기존 &lt;code&gt;AGENTS.md&lt;/code&gt;를 그대로 옮기는 것이 아니라, 공통 원칙과 모듈별 규칙을 분리해야 했다. 규칙을 작게 나누면 모든 작업에 불필요한 문맥을 주입하지 않으면서도 필요한 순간에 더 구체적인 지침을 적용할 수 있다.&lt;/p&gt;</description></item><item><title>TIL. Jun 16, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-16/</link><pubDate>Tue, 16 Jun 2026 20:29:07 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-16/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Antigravity IDE의 에이전트, 에디터, 터미널, 브라우저 구조 살펴보기&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/devbox-light-server-04-file-storage/"&gt;File Storage 구현 순서와 &lt;code&gt;StorageService&lt;/code&gt; 설계&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;Antigravity는 에디터 안에서 에이전트가 작업을 수행하고, 브라우저와 터미널을 사용해 결과를 검증하는 개발 환경이다. Agent는 기능 개발이나 버그 수정처럼 실제 작업을 담당하고, Tab은 자동완성에 가깝다.&lt;/p&gt;
&lt;p&gt;File Storage는 먼저 계약을 만들고, 그 다음 &lt;code&gt;fs/promises&lt;/code&gt; 기반 구현체와 테스트를 추가한 뒤, Express와 분리된 Service를 얹는 순서로 진행하기로 했다. 처음부터 multipart 업로드까지 확장하지 않고, JSON과 단순한 파일 콘텐츠로 흐름을 검증하는 것도 중요한 범위 조절이었다.&lt;/p&gt;</description></item><item><title>TIL. Jun 11, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-11/</link><pubDate>Thu, 11 Jun 2026 21:36:55 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-11/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LeetCode 3558 풀이&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/devbox-light-server-02-db-crud/"&gt;DB 모듈에서 capability와 use case 분리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/devbox-light-server-04-file-storage/"&gt;File Storage 모듈의 계약과 서비스 설계&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;기존에는 Route가 &lt;code&gt;Database&lt;/code&gt; 인터페이스를 직접 사용했다. 리팩터링 후에는 &lt;code&gt;Route -&amp;gt; DatabaseService -&amp;gt; RecordStore -&amp;gt; InMemoryRecordStore&lt;/code&gt; 흐름으로 바꾸었다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RecordStore&lt;/code&gt;는 레코드를 저장하고 꺼내는 교체 가능한 capability이고, &lt;code&gt;DatabaseService&lt;/code&gt;는 여러 저장소 동작을 조합하는 use case다. 예를 들어 &lt;code&gt;replace&lt;/code&gt; 이후 갱신된 레코드를 반환하거나, 삭제 결과에 따라 오류를 판단하는 흐름은 Service가 맡는다.&lt;/p&gt;
&lt;p&gt;File Storage도 같은 기준을 적용했다. 계약은 &lt;code&gt;key&lt;/code&gt;와 &lt;code&gt;Uint8Array&lt;/code&gt;만 사용해 작고 명시적으로 만들고, 로컬 파일 시스템이나 경로 검증은 구현체 안에 가둔다.&lt;/p&gt;</description></item><item><title>TIL. Jun 9, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-09/</link><pubDate>Tue, 09 Jun 2026 20:48:13 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-09/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;LeetCode 3689, 2574 풀이&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dev-data-server-light&lt;/code&gt;의 &lt;code&gt;AGENTS.md&lt;/code&gt; 구조 정리&lt;/li&gt;
&lt;li&gt;루트와 모듈별 개발 규칙의 중복 검토&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;새 디렉토리 구조에서는 공통 원칙을 루트 &lt;code&gt;AGENTS.md&lt;/code&gt;에 모으고, 모듈에만 해당하는 규칙은 해당 모듈의 문서에 두는 방향이 적절하다.&lt;/p&gt;
&lt;p&gt;루트에는 TypeScript, Express, Vitest 같은 기술과 전체 아키텍처, 테스트 원칙을 둔다. 반면 DB 모듈의 레코드 모델이나 저장소 구현 규칙처럼 다른 모듈이 알 필요 없는 내용은 DB 문서에 남긴다.&lt;/p&gt;
&lt;p&gt;중복된 규칙은 단순히 길이의 문제가 아니다. 같은 내용이 여러 파일에 있으면 나중에 한쪽만 수정될 수 있고, AI가 서로 다른 지침으로 해석할 가능성도 생긴다.&lt;/p&gt;</description></item><item><title>TIL. Jun 8, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-08/</link><pubDate>Mon, 08 Jun 2026 21:04:28 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-08/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/devbox-light-server-00-concept/"&gt;&lt;code&gt;dev-data-server-light&lt;/code&gt;의 계층형 구조를 모듈형 구조로 바꾸는 작업 검토&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;가 새 디렉토리 구조와 충돌하지 않도록 정리&lt;/li&gt;
&lt;li&gt;Database, Route, Service의 책임 재검토&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;p&gt;기존 구조는 &lt;code&gt;routes&lt;/code&gt;, &lt;code&gt;services&lt;/code&gt;, &lt;code&gt;db&lt;/code&gt;처럼 계층별로 나뉘어 있었다. 새 구조에서는 모듈이 자신의 계약, 구현체, 서비스, 라우트를 함께 소유하도록 바꾸려 했다.&lt;/p&gt;
&lt;p&gt;계층형 구조에서는 &lt;code&gt;AGENTS.md&lt;/code&gt;에 각 계층의 역할을 적기 쉬웠지만, 모듈형 구조에서는 모듈의 책임과 공개 API를 기준으로 규칙을 작성해야 한다. 구조가 바뀌면 문서도 함께 바뀌어야 하며, 기존 규칙을 억지로 유지하면 오히려 AI가 잘못된 경계를 학습하게 된다.&lt;/p&gt;</description></item><item><title>TIL. Jun 4, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-06-04/</link><pubDate>Thu, 04 Jun 2026 20:17:42 +0900</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-06-04/</guid><description>&lt;h2 id="오늘-한-내용"&gt;오늘 한 내용&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kelly-chui.github.io/posts/devbox-light-server-02-db-crud/"&gt;&lt;code&gt;dev-data-server-light&lt;/code&gt;의 DB 모듈 설계 정리&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;System 모듈과 DB 인터페이스 구현 방향 검토&lt;/li&gt;
&lt;li&gt;저장소와 애플리케이션 로직의 경계 정리&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="배운-내용"&gt;배운 내용&lt;/h2&gt;
&lt;h3 id="이름도-설계의-일부"&gt;이름도 설계의 일부&lt;/h3&gt;
&lt;p&gt;처음에는 &lt;code&gt;DocumentStore&lt;/code&gt;, &lt;code&gt;StoredDocument&lt;/code&gt;, &lt;code&gt;DocumentBody&lt;/code&gt;라는 이름을 사용했다. 하지만 &lt;a href="https://kelly-chui.github.io/posts/devbox-light-server-02-db-crud/"&gt;DB CRUD 인터페이스를 설계하는 과정&lt;/a&gt;에서 이 이름들이 프로젝트가 특정 Document Database를 전제로 한다는 인상을 준다는 것을 발견했다.&lt;/p&gt;
&lt;p&gt;In-Memory, SQL, JSON File 등 여러 구현을 염두에 둔다면 인터페이스도 구현 방식에서 자유로워야 한다. 그래서 &lt;code&gt;RecordStore&lt;/code&gt;, &lt;code&gt;StoredRecord&lt;/code&gt;, &lt;code&gt;RecordData&lt;/code&gt;처럼 더 중립적인 이름으로 바꿨다.&lt;/p&gt;</description></item><item><title>TIL. May 21, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-05-21/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-05-21/</guid><description>&lt;h1 id="요약"&gt;요약&lt;/h1&gt;
&lt;p&gt;LeetCode 문제를 풀면서 자료의 표현 방식이 성능에 큰 영향을 준다는 점을 다시 확인했다. 또한 Express의 &lt;code&gt;req&lt;/code&gt;, &lt;code&gt;res&lt;/code&gt;, &lt;code&gt;next()&lt;/code&gt;가 어떻게 협력하여 요청을 처리하는지 파이프라인 관점에서 정리했다.&lt;/p&gt;
&lt;h2 id="배운-것"&gt;배운 것&lt;/h2&gt;
&lt;h3 id="leetcode-3043-최적화"&gt;LeetCode 3043 최적화&lt;/h3&gt;
&lt;p&gt;LeetCode 3043번 문제를 풀었다. 두 정수형 배열에 있는 원소들 중 임의의 두 수를 선택했을 때, 공통의 일치하는 prefix의 최대 길이를 구하는 문제였다.&lt;/p&gt;
&lt;p&gt;우선, 각 배열의 길이가 최대 50000이기 때문에, 가능한 모든 쌍을 만들어서 크기를 구하는 방식으로 하면 시간복잡도가 O(n²)이 되어서 문제를 제 시간 안에 해결하기 힘들다. (n은 둘 중 긴 배열의 원소의 개수)&lt;/p&gt;</description></item><item><title>TIL. May 19, 2026</title><link>https://kelly-chui.github.io/til/2026/til-2026-05-19/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/til/2026/til-2026-05-19/</guid><description>&lt;h1 id="요약"&gt;요약&lt;/h1&gt;
&lt;p&gt;Express의 핵심 구성 요소와 요청 처리 흐름을 정리했다. 특히 Middleware가 특정 객체가 아니라 요청 처리 과정에서 동작하는 함수들의 역할이라는 점과, Express가 함수형 체인이 아닌 공유 객체(&lt;code&gt;req&lt;/code&gt;, &lt;code&gt;res&lt;/code&gt;)를 사용하는 파이프라인 구조라는 점을 이해하게 되었다.&lt;/p&gt;
&lt;h2 id="배운-것"&gt;배운 것&lt;/h2&gt;
&lt;h3 id="오늘-공부한-내용"&gt;오늘 공부한 내용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Express의 App, Router, Middleware&lt;/li&gt;
&lt;li&gt;Express의 동작&lt;/li&gt;
&lt;li&gt;Express의 간단한 내부 구조&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="express의-핵심-구성-요소"&gt;Express의 핵심 구성 요소&lt;/h2&gt;
&lt;p&gt;처음에는 Express를 iOS의 MVC에서 View를 제거한 형태 정도로 생각했다. Route Handler가 Controller 역할을 하는 것이라고 생각했다.
Express를 구성하는 핵심 요소는 크게 다음과 같다.&lt;/p&gt;</description></item><item><title>미방문록. PoC 대표 색상 추출 Picker 만들기</title><link>https://kelly-chui.github.io/posts/mibangmurok-dev-log-colorpicker/</link><pubDate>Mon, 09 Feb 2026 17:36:10 +0900</pubDate><guid>https://kelly-chui.github.io/posts/mibangmurok-dev-log-colorpicker/</guid><description>&lt;img src="https://kelly-chui.github.io/posts/mibangmurok-dev-log-colorpicker/image-001-optimized-image.webp" alt="" loading="lazy"&gt;
&lt;p&gt;음식 사진에서 색상을 뽑아서 카드의 배경색에 적용하는 기능을 구현해야 했다.&lt;/p&gt;
&lt;h2 id="처음-생각한-방향"&gt;처음 생각한 방향&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;원본 이미지를 그대로 다루면 비용이 크다.&lt;/li&gt;
&lt;li&gt;색이 너무 많으면 후보가 지저분해진다.&lt;/li&gt;
&lt;li&gt;원하는 색이 반드시 많이 나오는 색은 아니다.&lt;/li&gt;
&lt;li&gt;결과를 화면에 어떻게 보여줄지도 같이 고민해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="직접-구현해보자"&gt;직접 구현해보자.&lt;/h2&gt;
&lt;p&gt;외부 라이브러리를 쓰기보다는, 가능한 경우에는 항상 먼저 구현해보고 그 이후에 외부 라이브러리를 쓰는 방향을 선호하기 때문에, 직접 구현해보기로 했다.&lt;/p&gt;
&lt;p&gt;학부 시절에 이미지 프로세싱을 하기도 했고 나름대로 흥미롭게 접근했다.&lt;/p&gt;
&lt;h3 id="coregraphics에서-픽셀-읽기"&gt;CoreGraphics에서 픽셀 읽기&lt;/h3&gt;
&lt;p&gt;색상을 추출하려면 결국 이미지의 픽셀 값에 접근해야 했다.&lt;/p&gt;</description></item><item><title>Archive. NVIDIA Physical AI 생태계 정리 노트</title><link>https://kelly-chui.github.io/posts/archive-physical-ai/</link><pubDate>Fri, 06 Feb 2026 01:39:00 +0900</pubDate><guid>https://kelly-chui.github.io/posts/archive-physical-ai/</guid><description>&lt;p&gt;최근 NVIDIA의 피지컬 AI 생태계를 접할 기회가 있었는데, Omniverse, Isaac Sim, Cosmos, GR00T처럼 처음 보는 용어가 한꺼번에 등장해서 각각이 어떤 역할을 하는지 궁금해졌다.&lt;/p&gt;
&lt;p&gt;조금 찾아보니 개별 기술을 각각 봐서 이해하긴 어렵고, 전체 구조를 보면서 어떤 역할을 하는지 이해하는 것이 중요하다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;그래서 나중에 다시 봐도 흐름을 빠르게 떠올릴 수 있도록 핵심 개념을 간단히 정리했다.&lt;/p&gt;
&lt;h2 id="피지컬-ai"&gt;피지컬 AI&lt;/h2&gt;
&lt;p&gt;현실 세계를 인식 → 판단 → 물리적으로 행동하는 AI 시스템 전체를 의미한다. 디지털 AI와 달리 센서 불확실성, 실시간 제어, 물리 상호작용이 핵심 난이도다. (현직자도 단순히 소프트웨어로 처리하는 것 만으로는 충분하지 않다고 했다.)&lt;/p&gt;</description></item><item><title>Algorithm. Kadane's Algorithm</title><link>https://kelly-chui.github.io/posts/cs-algorithm-kadanes-algorithm/</link><pubDate>Tue, 25 Nov 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-algorithm-kadanes-algorithm/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;1차원 배열이 주어졌을 때, 연속된 구간의 최대 합을 구하는 알고리즘을 카데인 알고리즘이라고 한다.&lt;/p&gt;
&lt;p&gt;예를 들어 다음 배열이 있다면,&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[-2, 1, -3, 4, -1, 2, 1, -5, 4]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;연속된 구간 &lt;code&gt;[4, -1, 2, 1]&lt;/code&gt;의 합인 &lt;code&gt;6&lt;/code&gt;이 가장 크다.&lt;/p&gt;
&lt;p&gt;카데인 알고리즘은 앞에서 계산한 결과를 재활용하여 배열을 한 번만 순회한다. 따라서 시간 복잡도 &lt;code&gt;O(n)&lt;/code&gt;, 공간 복잡도 &lt;code&gt;O(1)&lt;/code&gt;로 문제를 해결할 수 있다.&lt;/p&gt;
&lt;h2 id="아이디어"&gt;아이디어&lt;/h2&gt;
&lt;p&gt;현재 원소에서 끝나는 연속 구간의 최대 합을 유지하고 다음 원소를 만났을 때 기존 구간을 이어가는 것과 현재 원소부터 새로운 구간을 시작하는 것 중 더 큰 값을 선택한다.&lt;/p&gt;</description></item><item><title>Docker. Dockerfile 작성하기</title><link>https://kelly-chui.github.io/posts/devops-docker-04-writing-dockerfile/</link><pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-docker-04-writing-dockerfile/</guid><description>&lt;p&gt;컨테이너를 실행하려면 먼저 이미지가 필요하고, 이미지는 &lt;code&gt;Dockerfile&lt;/code&gt;이라는 파일을 통해 생성한다.&lt;/p&gt;
&lt;p&gt;예제 Dockerfile을 기준으로 각 명령어가 어떤 역할을 하는지 살펴본다.&lt;/p&gt;
&lt;h2 id="dockerfile-구조-살펴보기"&gt;Dockerfile 구조 살펴보기&lt;/h2&gt;
&lt;p&gt;먼저 예제 Dockerfile을 보자.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-docker" data-lang="docker"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;python:3.13&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/local/app&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Install the application dependencies&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; requirements.txt ./&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; pip install --no-cache-dir -r requirements.txt&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Copy in the source code&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; src ./src&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;8080&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Setup an app user so the container doesn&amp;#39;t run as the root user&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; useradd app&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;uvicorn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;app.main:app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--host&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--port&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;8080&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이제 위 Dockerfile을 한 줄씩 살펴보자.&lt;/p&gt;</description></item><item><title>Docker. 내 애플리케이션 Dockerizing 하기</title><link>https://kelly-chui.github.io/posts/devops-docker-06-dockerizing/</link><pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-docker-06-dockerizing/</guid><description>&lt;h2 id="0-기반-파일"&gt;0. 기반 파일&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/nice-card/express-example"&gt;https://github.com/nice-card/express-example&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="1-프로젝트-위치-확인"&gt;1. 프로젝트 위치 확인&lt;/h2&gt;
&lt;p&gt;현재 경로를 프로젝트 경로로 설정하고 확인하기&lt;/p&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-docker-06-dockerizing/image-001-optimized-image.webp"&gt;&lt;h2 id="2--dockerfile-dockerignore-추가"&gt;2. Dockerfile, .dockerignore 추가&lt;/h2&gt;
&lt;p&gt;프로젝트 루트에 Dockerfile을 새로 만들기.&lt;/p&gt;
&lt;h3 id="dockerfile"&gt;Dockerfile&lt;/h3&gt;
&lt;p&gt;프로젝트 루트에 만들기.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-docker" data-lang="docker"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# === build stage ===&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/app&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; package*.json ./&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; npm ci &lt;span class="c1"&gt;# dev 포함 (tsc 사용)&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; . .&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; npm run build &lt;span class="c1"&gt;# dist/ 생성&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# === runtime stage ===&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:20-alpine&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/app&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ENV&lt;/span&gt; &lt;span class="nv"&gt;NODE_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; package*.json ./&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt; npm ci --omit&lt;span class="o"&gt;=&lt;/span&gt;dev &lt;span class="c1"&gt;# 런타임에 필요한 것만&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# 빌드 결과만 가져오기&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;COPY&lt;/span&gt; --from&lt;span class="o"&gt;=&lt;/span&gt;build /app/dist ./dist&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;3000&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CMD&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;npm&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;start&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# package.json의 &amp;#34;start&amp;#34;: &amp;#34;node dist/index.js&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="dockerignore"&gt;.dockerignore&lt;/h3&gt;
&lt;p&gt;불필요한 파일이 이미지에 안 들어가게 막는 용도&lt;/p&gt;</description></item><item><title>Docker. 이미지 Build하고 Push하기</title><link>https://kelly-chui.github.io/posts/devops-docker-05-build-and-push/</link><pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-docker-05-build-and-push/</guid><description>&lt;h2 id="사전준비하기--docker-hub"&gt;사전준비하기 &amp;amp; Docker Hub&lt;/h2&gt;
&lt;h3 id="docker-hub"&gt;Docker Hub&lt;/h3&gt;
&lt;p&gt;Docker 이미지를 공유하기 위해서는 이미지를 저장할 공간이 필요하고, 이 때 Docker Hub가 이미지 저장소로 사용된다. 다른 사람들이 올린 이미지를 검색하여 실행하거나 자신의 이미지를 기반으로 사용할 수 있는 공간을 제공한다.&lt;/p&gt;
&lt;h3 id="컨테이너-이미지"&gt;컨테이너 이미지&lt;/h3&gt;
&lt;p&gt;컨테이너 이미지는 애플리케이션을 실행하기 위한 파일, config, 종속성을 모두 포함한 표준화된 패키지이다. 이미지를 배포하면 다른 사람과 공유할 수 있다.&lt;/p&gt;
&lt;h2 id="docker-hub에-이미지-푸시하기"&gt;Docker Hub에 이미지 푸시하기&lt;/h2&gt;
&lt;p&gt;GitHub가 소스 코드를 저장하는 것처럼 Docker Hub는 컨테이너 이미지를 저장한다.&lt;/p&gt;</description></item><item><title>Docker. Docker Desktop 실습해보기</title><link>https://kelly-chui.github.io/posts/devops-docker-03-docker-desktop-lab/</link><pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-docker-03-docker-desktop-lab/</guid><description>&lt;h2 id="설치하기"&gt;설치하기&lt;/h2&gt;
&lt;p&gt;공식 문서에 설치 가이드 설명 잘 되어있으니 알아서&amp;hellip;&lt;/p&gt;
&lt;h2 id="첫-번째-컨테이너-실행하기"&gt;첫 번째 컨테이너 실행하기&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run -d -p 8080:80 docker/welcome-to-docker&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; 에서 이 컨테이너의 프론트엔드 방문 가능.&lt;/p&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-docker-03-docker-desktop-lab/image-001-optimized-image.webp"&gt;&lt;h2 id="docker-desktop-사용해보기"&gt;Docker Desktop 사용해보기&lt;/h2&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-docker-03-docker-desktop-lab/image-002-optimized-image.webp"&gt;&lt;h3 id="컨테이너-탭"&gt;컨테이너 탭&lt;/h3&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-docker-03-docker-desktop-lab/image-006-optimized-image.webp"&gt;&lt;ul&gt;
&lt;li&gt;Logs — &lt;code&gt;docker logs &amp;lt;container-name&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;컨테이너 내부에서 실행 중인 프로세스의 표준 출력을 그대로 보여줌.&lt;/li&gt;
&lt;li&gt;디버깅할 때 많이 사용하는 부분&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Inspect — &lt;code&gt;docker inspect &amp;lt;container-name&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;컨테이너의 환경 변수, 포트 바인딩, 실행 명령, 마운트 경로, 네트워크, 상태 등 메타데이터를 JSON으로 보여줌&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Bind mounts
&lt;ul&gt;
&lt;li&gt;로컬 호스트와 컨테이너 사이의 폴더 연결 정보를 보여줌
&lt;ul&gt;
&lt;li&gt;ex) &lt;code&gt;-v ~/project:/app&lt;/code&gt; → 내 컴퓨터의 &lt;code&gt;~/project&lt;/code&gt; 폴더가 컨테이너 내부 &lt;code&gt;/app&lt;/code&gt;에 연결됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;로컬 파일 수정 시 컨테이너에 즉시 반영되기 때문에 개발할 때 자주 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Exec — &lt;code&gt;docker exec -it &amp;lt;container-name&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;실행 중인 컨테이너 내부에 직접 명령어를 입력할 수 있는 쉘 세션을 엶.&lt;/li&gt;
&lt;li&gt;컨테이너 내부 구조 탐색, 빠른 테스트, 수동 디버깅에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Files — &lt;code&gt;docker cp&lt;/code&gt;, &lt;code&gt;docker exec ls&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;컨테이너 내부의 파일 시스템 탐색&lt;/li&gt;
&lt;li&gt;호스트 ↔ 컨테이너 간 파일을 복사할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Stats: &lt;code&gt;docker stats &amp;lt;container-name&amp;gt;&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;컨테이너의 실시간 리소스 사용량(CPU, 메모리, 네트워크, I/O) 등을 모니터링&lt;/li&gt;
&lt;li&gt;성능 문제나 리소스 병목을 추적할 때 사용&lt;/li&gt;
&lt;li&gt;여러 컨테이너 동시 모니터링 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="직접-컨테이너를-사용해서-개발해보기"&gt;직접 컨테이너를 사용해서 개발해보기&lt;/h2&gt;
&lt;h3 id="0-프로젝트-클론"&gt;0. 프로젝트 클론&lt;/h3&gt;
&lt;p&gt;우선 Docker에서 제공하는 예제 앱 가져오기&lt;/p&gt;</description></item><item><title>Docker. Docker 시작하기</title><link>https://kelly-chui.github.io/posts/devops-docker-01-getting-started/</link><pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-docker-01-getting-started/</guid><description>&lt;h2 id="docker"&gt;Docker&lt;/h2&gt;
&lt;p&gt;애플리케이션 개발, 배포 및 실행을 위한 개방형 플랫폼&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Note.&lt;/p&gt;
&lt;p&gt;컨테이너는 개발 환경 자체가 아니라 애플리케이션를 실행하는 격리된 프로세스다. 일반적으로 개발은 호스트 환경에서 이루어지고, 컨테이너는 실행 및 테스트 환경으로 사용된다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 그런데 vscode에서 쓰는 dev container는&amp;hellip;?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="컨테이너를-사용한-앱-개발"&gt;컨테이너를 사용한 앱 개발&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Docker 컨테이너 안에서 앱을 띄우기 때문에 “환경이 달라서 동작하지 않는다”와 같은 문제 해결&lt;/li&gt;
&lt;li&gt;ex. Node, Python, MySQL같은 것을 도커로 묶어서 개발&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="컨테이너는-완전한-실행-단위"&gt;컨테이너는 완전한 실행 단위&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;컨테이너 하나는 완전한 실행 단위이기 때문에 QA, 테스트, CI/CD 환경에서 그대로 사용&lt;/li&gt;
&lt;li&gt;같은 이미지 → 같은 코드, 같은 환경 → 어디서든 일관된 실행이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="애플리케이션을-컨테이너-형태로-배포"&gt;애플리케이션을 컨테이너 형태로 배포&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;클라우드나 로컬 서버로 그대로 옮겨서 실행하면 된다.&lt;/li&gt;
&lt;li&gt;수명 주기 관리
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;push&lt;/code&gt; 모든 것을 Docker가 명령어 단위로 관리해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="반응형-배포-및-확장"&gt;반응형 배포 및 확장&lt;/h3&gt;
&lt;p&gt;Docker는 어디서나 똑같이 돌고, 원하면 즉시 늘리거나 줄일 수 있다.&lt;/p&gt;</description></item><item><title>Docker. 컨테이너와 이미지</title><link>https://kelly-chui.github.io/posts/devops-docker-02-containers-and-images/</link><pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-docker-02-containers-and-images/</guid><description>&lt;h2 id="컨테이너"&gt;컨테이너&lt;/h2&gt;
&lt;p&gt;애플리케이션의 구성 요소(프론트엔드, API, DB 등)을 각각 격리된 프로세스로 실행하는 환경.&lt;/p&gt;
&lt;h3 id="특징"&gt;특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;호스트의 어떤 환경에도 의존하지 않고, 필요한 라이브러리와 설정을 모두 포함한 독립된 환경으로 존재한다.&lt;/li&gt;
&lt;li&gt;서로 다른 컨테이너는 격리되어 있어서 하나가 망가져도 다른 컨테이너에 영향을 주지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="컨테이너-vs-vm"&gt;컨테이너 vs. VM&lt;/h3&gt;
&lt;p&gt;VM은 자체 커널, 드라이버, 프로그램을 갖춘 완전한 운영체제이기 때문에, 단일 애플리케이션을 분리하기 위해 VM을 사용하는 것은 오버헤드가 크다.&lt;/p&gt;
&lt;p&gt;컨테이너는 실행에 필요한 모든 파일을 갖춘 고립된 프로세스이다. 여러 컨테이너를 실행하더라도 모두 동일한 커널을 공유하므로, 더 적은 인프라에서 많은 애플리케이션을 실행할 수 있다.&lt;/p&gt;</description></item><item><title>Node. TypeScript 프로젝트 초기화하기</title><link>https://kelly-chui.github.io/posts/node-typescript-project-initialization/</link><pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/node-typescript-project-initialization/</guid><description>&lt;h2 id="새로운-노드-프로젝트-생성하기"&gt;새로운 노드 프로젝트 생성하기&lt;/h2&gt;
&lt;h3 id="npm-초기화부터"&gt;npm 초기화부터&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm init -y&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Node 프로젝트를 초기화한다. 이 명령을 실행하면 현재 디렉터리에 &lt;code&gt;package.json&lt;/code&gt; 파일이 생성되고, Node와 npm은 이를 기준으로 프로젝트를 관리한다.&lt;/p&gt;
&lt;h3 id="npm-install"&gt;npm install&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-zsh" data-lang="zsh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install -D typescript tsx @types/node @types/express&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npm install&lt;/code&gt;: 필요한 패키지를 설치하는 명령이다. 뒤에 패키지 이름을 지정하면 해당 패키지를 설치하고, &lt;code&gt;package.json&lt;/code&gt;에도 자동으로 기록한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-D&lt;/code&gt;: &lt;code&gt;--save-dev&lt;/code&gt;의 약자이다. 개발 과정에서만 사용하는 패키지를 &lt;code&gt;devDependencies&lt;/code&gt;에 추가한다. TypeScript처럼 빌드 과정에서만 필요한 도구들이 여기에 해당한다.&lt;/li&gt;
&lt;li&gt;패키지
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;typescript&lt;/code&gt;: TS 컴파일러 (tsc 명령어 제공)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tsx&lt;/code&gt;: TS 파일을 빌드 없이 바로 실행하게 해주는 도구 (dev 서버용)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@types/node&lt;/code&gt;: Node.js의 타입 정의&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@types/express&lt;/code&gt;: Express 라이브러리의 타입 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note.&lt;/p&gt;</description></item><item><title>JavaScript. 모듈 시스템</title><link>https://kelly-chui.github.io/posts/javascript-module-system/</link><pubDate>Tue, 07 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/javascript-module-system/</guid><description>&lt;p&gt;프로젝트가 커질수록 모든 코드를 하나의 파일에 작성하기는 어렵다. 그래서 JavaScript는 기능별로 코드를 여러 파일로 나누어 관리하며, 각각의 파일을 모듈(Module)이라고 한다.&lt;/p&gt;
&lt;p&gt;모듈 시스템은 이러한 모듈을 다른 파일에서 가져오고 내보내는 방법을 정의한다.&lt;/p&gt;
&lt;h2 id="주요-모듈-시스템"&gt;주요 모듈 시스템&lt;/h2&gt;
&lt;h3 id="commonjs-cjs"&gt;CommonJS (CJS)&lt;/h3&gt;
&lt;p&gt;CommonJS는 Node.js 초창기부터 사용된 모듈 시스템이다. &lt;code&gt;require&lt;/code&gt;로 다른 모듈을 가져오고, &lt;code&gt;module.exports&lt;/code&gt;로 외부에 공개할 값을 내보낸다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// math.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// main.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;math&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;./math&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위 예시에서 &lt;code&gt;module.exports&lt;/code&gt;는 &lt;code&gt;add&lt;/code&gt; 함수를 다른 파일에서도 사용할 수 있도록 내보낸다. &lt;code&gt;main.js&lt;/code&gt;에서는 &lt;code&gt;require&lt;/code&gt;를 통해 해당 모듈을 가져와 &lt;code&gt;math.add()&lt;/code&gt;를 호출한다.&lt;/p&gt;</description></item><item><title>Node. Node.js 소개</title><link>https://kelly-chui.github.io/posts/node-nodejs-introduction/</link><pubDate>Sun, 05 Oct 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/node-nodejs-introduction/</guid><description>&lt;p&gt;Node.js는 브라우저 밖에서도 JavaScript를 실행할 수 있게 해주는 런타임이다.&lt;/p&gt;
&lt;h2 id="구조"&gt;구조&lt;/h2&gt;
&lt;p&gt;Node.js를 설치하면 JavaScript 런타임 하나만 설치되는 것이 아닌, 프로젝트 관리, 외부 라이브러리, 개발 도구를 실행하기 위한 여러 구성 요소가 함께 설치된다.&lt;/p&gt;
&lt;h3 id="node"&gt;Node&lt;/h3&gt;
&lt;p&gt;JavaScript 실행 환경이다. 브라우저 외부에서 JS를 실행할 수 있게 해준다.&lt;/p&gt;
&lt;p&gt;간단한 파일은 다음처럼 직접 실행할 수도 있다. (다른 언어들과 비슷하다.)&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-zsh" data-lang="zsh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;node &amp;lt;FILE-NAME&amp;gt;.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="npmnode-package-manager"&gt;npm(Node Package Manager)&lt;/h3&gt;
&lt;p&gt;Node 프로젝트의 패키지 관리자이다. 외부 라이브러리를 설치하고, 제거하고, 프로젝트의 의존성을 관리한다.&lt;/p&gt;
&lt;p&gt;외부 라이브러리를 설치할 때는 다음 명령을 사용한다.&lt;/p&gt;</description></item><item><title>SwiftUI 상태 관리</title><link>https://kelly-chui.github.io/posts/swiftui-swiftui-property-wrapper/</link><pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swiftui-swiftui-property-wrapper/</guid><description>&lt;h2 id="상태를-누가-소유하고-어떻게-전달해야-하는가"&gt;상태를 누가 소유하고 어떻게 전달해야 하는가&lt;/h2&gt;
&lt;p&gt;SwiftUI에서는 상태를 저장하거나 다른 뷰에 전달할 때 프로퍼티 래퍼를 사용한다.&lt;/p&gt;
&lt;p&gt;이 상태를 현재 뷰가 직접 가지고 있는지, 부모 뷰에서 전달받는지, 아니면 별도의 객체가 관리하는지에 따라 사용하는 래퍼가 달라진다.&lt;/p&gt;
&lt;h3 id="상위-뷰--하위-뷰"&gt;상위 뷰 → 하위 뷰&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;@State → @Binding&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;상위 뷰가 상태를 소유하고, 하위 뷰는 해당 상태를 수정할 수 있도록 &lt;code&gt;@Binding&lt;/code&gt;으로 전달받는다.&lt;/p&gt;
&lt;h3 id="뷰-모델--뷰--하위-뷰"&gt;뷰 모델 → 뷰 → 하위 뷰&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ObservableObject&lt;/code&gt; 프로토콜을 채택한 뷰 모델에서는, 변경을 알려야 하는 값을 &lt;code&gt;@Published&lt;/code&gt; 프로퍼티로 선언한다.(이 뷰 모델을 뷰에서 주입받아 사용할 때는 보통 &lt;code&gt;@ObservedObject&lt;/code&gt;로 관찰함)&lt;/p&gt;</description></item><item><title>Swift Concurrency. Behind the Scenes - WWDC21</title><link>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-behind-the-scenes/</link><pubDate>Mon, 25 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swift-concurrency-behind-the-scenes/</guid><description>&lt;h2 id="threading-model"&gt;Threading model&lt;/h2&gt;
&lt;p&gt;뉴스 피드 리더 앱을 예로 들어보자. 앱의 상위 컴포넌트는 다음과 같이 나눌 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사용자 인터페이스를 담당하는 메인 스레드&lt;/li&gt;
&lt;li&gt;사용자가 구독한 뉴스 피드를 추적하는 데이터베이스&lt;/li&gt;
&lt;li&gt;최신 콘텐츠를 가져오는 네트워킹 서브시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;사용자가 최신 뉴스를 요청하면 다음과 같은 흐름으로 처리할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;메인 스레드에서 이벤트 제스처 처리&lt;/li&gt;
&lt;li&gt;데이터베이스 작업을 처리하는 직렬 큐로 요청을 비동기적으로 디스패치
&lt;ul&gt;
&lt;li&gt;작업을 다른 큐로 보내면 메인 스레드는 데이터베이스 작업을 기다리지 않고 사용자 입력에 계속 반응할 수 있다.&lt;/li&gt;
&lt;li&gt;직렬 큐가 상호 배제를 보장하므로 데이터베이스 접근을 순서대로 처리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터베이스 큐에선 사용자가 구독한 피드에 URLSession을 통해 콘텐츠를 다운로드하는 네트워크 요청을 스케줄링&lt;/li&gt;
&lt;li&gt;결과가 도착하면 URLSession의 콜백이 Delegate Queue 위에서 호출되어서 각 결과의 Completion Handler가 동기적으로 데이터베이스를 업데이트한다.&lt;/li&gt;
&lt;li&gt;MainThread를 깨워서 UI를 리프레시한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;보기에는 합리적인 방법이다. 메인 스레드를 블록하지 않으면서 네트워크 요청을 동시에 처리할 수 있기 때문이다.&lt;/p&gt;</description></item><item><title>Programmers. 미로 탈출 명령어</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-maze-escape-commands/</link><pubDate>Sat, 23 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-maze-escape-commands/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/150365"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/150365&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;분명히 배열(문자열)의 원소를 하나씩 채워나가야 하는 DFS 완전 탐색 스타일의 문제인데 k의 최대값이 2,500으로 너무 크다. 하지만 문제에서 주어진 조건들을 읽어보면 프루닝을 통해 백트래킹 문제로 만들 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;현재 위치와 종료 위치 사이의 맨하탄 거리가 남은 이동 횟수보다 적으면, 더 이상 탐색할 필요가 없다.
&lt;ul&gt;
&lt;li&gt;목표에 도달하지 못하는 분기이기 때문에, 분기를 버려야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;남은 이동 횟수와 현재 위치와 종료 위치 사이의 맨하탄 거리의 차가 홀수인 경우에도 더 이상 탐색할 필요가 없다.
&lt;ul&gt;
&lt;li&gt;이동 횟수는 고정이고, 두 위치의 거리보다 크다면 이동 횟수를 어딘가에서 소모해야한다. 그런데 다른 위치로 갔다가, 다시 현재 위치로 돌아올때 소모하는 값은 2이므로, 홀수인 경우에는 목적지에 절대 도달할 수 없게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;마지막으로, 탐색 순서를 잘 정했다면 처음으로 성공한 케이스가 곧 사전순에서 가장 앞선 순서가 된다. 한 번만 성공하게 되면 그 뒤의 모든 분기는 의미가 없어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이렇게 프루닝을 하면 완전 탐색으로 절대로 해결 불가능한 문제를 풀 수 있게 된다.&lt;/p&gt;</description></item><item><title>Programmers. 표 편집</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-table-edit/</link><pubDate>Thu, 14 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-table-edit/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/81303"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/81303&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;이 문제에서 핵심은 삭제된 칸을 건너 뛰면서 칸을 옮기는 것이다. 칸을 옮기는 횟수가 최대 1,000,000 번이라고 제한되어 있지만, 명령의 개수도 200,000 개 이므로 칸을 단순히 부울리언 값으로 켜고 끄면서 이동하는 것은 최악의 경우에 굉장히 많은 시간이 걸릴 것이다.&lt;/p&gt;
&lt;p&gt;여기서 생각해야할 점은 이 문제에서는 &amp;lsquo;랜덤 액세스&amp;rsquo;를 요구하지 않는다는 것이다. 문제에서 삭제된 칸을 복구할때 커서를 옮기지 않는다고 했으므로, 랜덤 액세스가 들어갈 부분은 처음 커서 위치를 지정하는 부분밖에 없다. 또한 중간에 있는 칸을 삭제하고 복구하는 작업들이 있으므로, 컨테이너 중간에서 삭제/삽입 연산이 쉬운 자료구조를 생각해야 하고, 바로 링크드 리스트가 떠올랐다.&lt;/p&gt;</description></item><item><title>Programmers. 합승 택시 요금</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-shared-taxi-fare/</link><pubDate>Thu, 14 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-shared-taxi-fare/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/72413"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/72413&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제를 간단히 하는 것이 중요하다. 이 문제에서 원하는 것은 S에서 시작해서 A와 B 노드로 가야하는데, 그 최단 거리를 요구하고 있다. 그러면 둘이 헤어지는 지점이 존재할 것이고, 이 헤어지는 지점은 S일 수도 있다(문제에서 주어진 내용이다). 그러면 헤어지는 지점을 M이라고 했을때, 우리가 구해야 하는 것은 S → M, M → A, M → B의 최단거리들의 합이다.&lt;/p&gt;
&lt;p&gt;문제가 최단거리를 구하는 문제로 단순화 되었다. 음수 사이클이 존재하지 않으므로, 다익스트라 알고리즘이나 플로이드 워셜 알고리즘을 사용하면 된다. 만약 다익스트라를 사용한다면 M을 우리가 모르므로 모든 노드에 대해서 다익스트라 알고리즘을 적용해보고 M을 찾아야 한다. 플로이드 워셜은 모든 노드 상호간의 최단거리를 알 수 있고, 노드의 개수도 200개가 상한이기 때문에 플로이드 워셜을 쓰는 것이 훨씬 간단하게 풀 수 있다.&lt;/p&gt;</description></item><item><title>Programmers. 인사고과</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-performance-review/</link><pubDate>Wed, 06 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-performance-review/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/152995"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/152995&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정렬 문제다. 두 개의 수를 가진 튜플(혹은 배열)이 있고, 두 수의 합이 아닌, 각 수를 개별적으로 두 값이 모두 작거나 큰지 판단해야 하는 경우에는 첫 번째 기준이 되는 값은 오름차순, 그리고 두 번째 기준이 되는 값은 내림차순으로 정렬하는 것이 일반적이다. 반대도 가능하고, 이 문제에서도 첫 번째 기준이 되는 값을 내림차순, 두 번째 기준이 되는 값을 오름차순으로 정렬하는 것이 더 편하다.&lt;/p&gt;
&lt;p&gt;순위를 셀 때도 조금은 최적화할 수 있다. 제거해야할 원소들을 제거하고 새로운 배열을 만드는 것이 아닌, 그냥 배열을 순회하면서, 기준이 되는 원소보다 큰 수를 카운트 하면 된다.&lt;/p&gt;</description></item><item><title>Programmers. 순위</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-ranking/</link><pubDate>Tue, 05 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-ranking/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/49191"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/49191&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;처음에 문제를 막 읽었을 때는 조금 어려워 보이지만, 문장을 살짝 다르게 해석해보자. &amp;lsquo;정확하게 순위를 매길 수 있는 선수의 수&amp;rsquo;를 알아야 하는데 정확하게 순위를 매긴다는 것은 어떨 때 성립할까? 특정 선수 A가 존재할 때, A와 서로 승패를 알 수 없는 선수 B가 존재하면 정확하게 순위를 매길 수 없는 것이다. 반대로 A가 다른 모든 선수들과 확실하게 승패의 결과를 알 수 있다면, 정확하게 순위를 매길 수 있다.&lt;/p&gt;
&lt;p&gt;문제에서는 경기 결과를 제공해주므로, 선수들의 실력을 간접적으로 알 수 있다. 실력을 수치화 해서 관리할 수 있으면 좋지만, 그럴게 할 수 없는 조건이고 그럴 필요도 없다. 단순하게 선수들간의 &amp;lsquo;승&amp;rsquo;, &amp;lsquo;패&amp;rsquo; 결과를 그래프로 관리해주면 된다. 승리 그래프와 패배 그래프를 따로 만들어서, 경기 결과를 그래프로 표현하고, 각 선수마다 이 선수가 승리할 선수, 패배할 선수의 수를 세어주면 된다. 특정 선수가 다른 모든 선수들과 확실하게 승패의 결과를 알 수 있다는 것은, 결국 승리할 선수와 패배할 선수의 합이 현재 선수를 제외한 나머지 선수의 수와 같은 것이기 때문이다.&lt;/p&gt;</description></item><item><title>Programmers. 풍선 터트리기</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-pop-balloons/</link><pubDate>Tue, 05 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-pop-balloons/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/68646"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/68646&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제의 조건은 쉬운데, 풀이 과정은 쉽지 않아보인다. 하지만 문제를 최대한 단순화해보자. 기본적으로, 인접한 두 풍선을 고를 수 있고 두 풍선중 번호가 더 큰 풍선을 터트려야 한다. 하지만 1회에 한정에서 번호가 더 작은 풍선을 터트릴 수 있다.&lt;/p&gt;
&lt;p&gt;일단 기본적으로 마지막까지 남을 수 있는 풍선의 개수를 세야 하므로 모든 풍선에 대해 확인해봐야 한다. 그리고 마지막까지 남을 수 있는 풍선이라고 했으므로, 항상 마지막에 고르는 두 풍선들 중 하나는 현재 내가 확인하고 싶은 풍선일 것이다.&lt;/p&gt;</description></item><item><title>Programmers. 거스름돈</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-change/</link><pubDate>Sun, 03 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-change/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/12907"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12907&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DP 문제다. 순열인지 조합인지 조심하면 쉽게 풀 수 있다. 문제에서 예시로 든 1, 2, 5원이 있을 때를 생각해보자. (5도 마찬가지지만) 2는 1의 배수이다. 따라서 순열로 하면 &amp;lsquo;3&amp;rsquo;을 만드는 경우에 1+1+1, 1+2, 2+1 이라는 세 가지 방법이 나오게 된다. 하지만 이 문제는 조합 문제이므로 중복을 제거해야한다.&lt;/p&gt;
&lt;p&gt;그러면 중복을 어떻게 제거해야 할까? 작은 동전부터 순서대로 만들면 된다. 이 방법이 조합 DP의 가장 기본적인 방법이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;가장 작은 동전을 써서 만들 수 있는 조합을 다 만든 다음 DP 테이블에 저장한다.&lt;/li&gt;
&lt;li&gt;작은 순서대로 (오름차순으로) 조합을 더한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이런 식으로 하면 중복을 방지할 수 있다. 위 예제로 따지면 1원짜리 동전을 먼저 써서 1+1+1을 우선 만들고, 다음에 2원을 써서 1+2를 만든다. 작은 순서대로 하므로 알고리즘 상에서 2+1 같은 방법을 만들지 않는다.&lt;/p&gt;</description></item><item><title>Programmers. 셔틀버스</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-shuttle-bus/</link><pubDate>Sun, 03 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-shuttle-bus/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/17678"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/17678&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;단순 구현으로 풀 수 있는 문제다. 문제를 단순화하면 조건에 맞는 최대 값을 구하는 문제이므로 바이너리 서치도 쓸 수 있겠다.&lt;/p&gt;
&lt;p&gt;우선 시간을 다루는 문제에서는 시간, 분을 분으로 통일하는 경우가 더 시간을 다루기 쉬워지는 경우가 많다. 예를 들어서 셔틀의 첫 도착 시간인 9:00을 540으로 바꾸는 것이다.&lt;/p&gt;
&lt;p&gt;그리고 &lt;code&gt;timetable&lt;/code&gt; 배열의 길이가 최대 2000이므로 모든 배열을 순회해도, 심지어 $O(n^2)$시간으로 순회해도 아무런 걱정이 없다. 따라서 앞 번호부터 순서대로 버스에 태우면 된다. 이제 마지막 버스인 경우에 콘이 탈 수 있는 여유가 있다면, 마지막 버스의 도착 시간을 리턴하면 되고, 만약 여유가 없다면, 마지막 버스에 마지막으로 타는 사람보다 &amp;lsquo;1분&amp;rsquo; 일찍 나오면 된다.&lt;/p&gt;</description></item><item><title>Swift Concurrency. 01. 도입 배경</title><link>https://kelly-chui.github.io/posts/swift-concurrency-01-introduction/</link><pubDate>Sun, 03 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swift-concurrency-01-introduction/</guid><description>&lt;p&gt;Swift Concurrency는 Swift 5.5에서 도입된 기능이다. &lt;code&gt;Foundation&lt;/code&gt;을 import 해야 쓸 수 있는 GCD와 다르게, Swift 언어 자체에 내장된 동시성 모델이다.&lt;/p&gt;
&lt;p&gt;Swift Concurrency는 크게 두 가지 부분으로 나뉘어진다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;async&lt;/code&gt;, &lt;code&gt;await&lt;/code&gt; 로 작성하는 새로운 동시성 모델&lt;/li&gt;
&lt;li&gt;애플리케이션을 여러 동시성 태스크로 분할하는 Actor&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 포스트에서는 Swift Concurrency의 도입 배경을 알아본다.&lt;/p&gt;
&lt;h2 id="gcd의-한계"&gt;GCD의 한계&lt;/h2&gt;
&lt;p&gt;GCD는 Objective-C에서부터 사용해온 애플이 만든 비동기 API다. Queue 기반으로 작업을 스케줄링 하고, 스레드 위에서 추상화 되어있기 때문에 스레드를 직접 생성하거나 관리할 필요가 없다.&lt;/p&gt;</description></item><item><title>Programmers. 디스크 컨트롤러</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-disk-controller/</link><pubDate>Sat, 02 Aug 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-disk-controller/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/42627"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42627&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;우선 순위대로 문제를 처리하므로 힙을 써야하는 것은 명확하다. 하지만, 이 힙을 어떻게 다루느냐가 더 중요한 문제이기 때문에 사실상 힙보다는 단순 구현 문제에 가깝다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;heapq&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;waitQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jobIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;totalReturnTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;jobIdx&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jobIdx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;requestTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jobIdx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heapq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heappush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waitQueue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestTime&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jobIdx&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;waitQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requestTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heapq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heappop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waitQueue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;returnTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;requestTime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;totalReturnTime&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;returnTime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;finished&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jobIdx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;totalReturnTime&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Programmers. 징검다리 건너기</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-crossing-stepping-stones/</link><pubDate>Tue, 22 Jul 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-crossing-stepping-stones/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/64062"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/64062&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;처음 문제를 읽어보고 바이너리 서치를 이용해야겠다고 생각했다. 결정해야 할 값을 건널 수 있는 최대 인원수로 맞춰놓고 바이너리 서치를 이용하여 찾으면 되기 때문이다.&lt;/p&gt;
&lt;p&gt;바이너리 서치를 이용한 알고리즘은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;바이너리 서치를 통해 찾고 싶은 값은 징검다리를 건널 수 있는 최대 인원 수이다.&lt;/li&gt;
&lt;li&gt;징검다리 하나의 내구도가 최대 2억이므로 1에서 2억까지의 범위 내에서 인원 수의 최대값을 찾는다
&lt;ol&gt;
&lt;li&gt;값이 유효한지 체크하는 방법은 징검다리에서 현재 인원 수가 밟은 수를 뺀 다음 0 이하의 징검다리 돌들이 연속되는 경우가 &lt;code&gt;k&lt;/code&gt;개 이하면 통과, 초과면 통과시키지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;바이너리 서치 결과를 리턴한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 코드의 시간 복잡도는 $N$이 &lt;code&gt;stones&lt;/code&gt; 배열의 크기, $M$이 돌 내구도의 최대값이라 했을 때 $O(N \log M)$이다. 돌 내구도의 최대값은 2억이고, 2의 30제곱이 약 10억이므로 30번 이내에 찾을 수 있다. 최대 20만 크기의 배열을 30번 정도 반복한다고 생각하면 충분히 시간 복잡도가 나온다.&lt;/p&gt;</description></item><item><title>iOS. 파일 시스템과 샌드박스</title><link>https://kelly-chui.github.io/posts/ios-file-system-sandbox/</link><pubDate>Mon, 21 Jul 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-file-system-sandbox/</guid><description>&lt;p&gt;앱은 종료된 뒤에도 데이터를 유지하기 위해 파일 시스템을 사용한다. iOS, macOS 같은 애플 플랫폼에서는 APFS(Apple File System)라는 파일 시스템을 쓴다. 애플은 사용자 파일과 앱 내부 파일을 분리해서 관리하는 것을 목표로 한다.&lt;/p&gt;
&lt;p&gt;개발자 문서에서는 파일 시스템의 목표를 다음과 같이 제시한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사용자 파일은 쉽게 찾을 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;앱 내부적으로 사용하는 파일은 사용자 눈에 띄지 않도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;많은 파일 시스템처럼 APFS도 디렉토리 구조를 통해 계층적으로 파일을 관리한다. 모든 디스크가 &amp;lsquo;단일 파일 컬렉션&amp;rsquo;을 구성한다는 점이 특징이다. 즉, 여러 디스크를 연결해도 사용자에게는 하나의 계층에 있는 것처럼 보인다.&lt;/p&gt;</description></item><item><title>Programmers. 단속 카메라</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-speed-camera/</link><pubDate>Mon, 21 Jul 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-speed-camera/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/42884"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42884&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;그리디 문제다. 그리디는 따로 정석 구현이 있는 알고리즘이 아니라 일종의 컨셉이지만, 배열 + 그리디면 잘 알다시피 정렬이 중요한 경우가 많다.&lt;/p&gt;
&lt;p&gt;단순하게 생각해보자, 문제에서 주어지는 것은 시작 위치와 종료 위치다. 그냥 종료하는 위치를 기준으로 오름차순 정렬한 후에 앞에서부터 탐색을 한다.&lt;/p&gt;
&lt;p&gt;현재 자동차의 종료 위치에 카메라를 설치하고, 다음 자동차를 살펴본다. 다음 자동차의 시작 위치가 이전 자동차의 종료 위치(즉 카메라가 설치된 위치)보다 앞에 있으면 다음 자동차도 설치된 카메라를 만나게 된다. 그렇지 않다면 또 그 자동차의 종료 위치에 카메라를 설치하면 된다.&lt;/p&gt;</description></item><item><title>Programmers. 불량 사용자</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-bad-user/</link><pubDate>Mon, 21 Jul 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-bad-user/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/64064"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/64064&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;일정 크기의 배열(혹은 컬렉션)을 만들어서 매칭되는지 확인해야 하는 문제다.&lt;/p&gt;
&lt;p&gt;DFS를 사용해서 모든 경우의 수를 만들기는 쉽지만, 그 경우의 수가 문제에서 제시하는 조건에 맞는지 확인하는 것은 어렵다. 따라서 알고리즘을 약간 수정해서 좀 더 효율적이고 만들기 쉬운 알고리즘을 만들어야 한다.&lt;/p&gt;
&lt;p&gt;알고리즘은 다음과 같다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;주어진 &lt;code&gt;banned_id&lt;/code&gt; 배열 원소 하나하나에 대응가능한 id를 &lt;code&gt;user_id&lt;/code&gt;에서 뽑아서 후보 &lt;code&gt;set&lt;/code&gt;에 넣는다.&lt;/li&gt;
&lt;li&gt;1번을 재귀적으로 진행한다. &lt;code&gt;set&lt;/code&gt;에 담는 이유는 id가 중복되면 안되기 때문이다.&lt;/li&gt;
&lt;li&gt;후보 set이 완성되면, 정답 &lt;code&gt;set&lt;/code&gt;에 저장한다. &lt;code&gt;set&lt;/code&gt;은 &lt;code&gt;set&lt;/code&gt;에 담을 수 없으므로 &lt;code&gt;frozenset&lt;/code&gt;을 이용한다.&lt;/li&gt;
&lt;li&gt;정답 &lt;code&gt;set&lt;/code&gt;의 개수를 리턴한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strB&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidateSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidateSet&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidateSet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidateSet&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;idSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;banned_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idSet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Programmers. 최고의 집합</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-best-set/</link><pubDate>Sun, 20 Jul 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-best-set/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/12987"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12987&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n&lt;/code&gt;의 값이 최대 10000, &lt;code&gt;s&lt;/code&gt;의 값이 최대 1000000의 값을 가질 수 있으므로 모든 경우의 수를 DFS로 탐색하는 것은 매우 비효율적이다.&lt;/p&gt;
&lt;p&gt;하지만 수학적 직관을 이용해 생각해보자. 예시로 주어진 s = 9, n = 2인 경우에서도 {4, 5}가 최고의 집합이다. 만약 s = 5, n = 2인 경우에는? {2, 3}이다. s = 10, n = 2인 경우는 {5, 5} 이다. 집합 원소들이 최대한 고르게 되어있을 때 원소들의 곱이 최대가 된다는 것(= 최고의 집합이라는 것)을 알 수 있다. 그러면 이 직관을 증명해보자.&lt;/p&gt;</description></item><item><title>Algorithm. Bit masking</title><link>https://kelly-chui.github.io/posts/cs-algorithm-bit-masking/</link><pubDate>Thu, 12 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-algorithm-bit-masking/</guid><description>&lt;h2 id="기본-소개"&gt;기본 소개&lt;/h2&gt;
&lt;p&gt;비트 마스킹은 비트 연산을 활용해서 집합을 구현하는 방법이다. 각 자리수의 비트는 하나의 원소를 나타내며, 이 원소들이 모여서 집합을 구성하게 된다.&lt;/p&gt;
&lt;p&gt;예를 들어, 원소 A, B, C, D를 각각 다음과 같이 표현할 수 있다:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mb"&gt;0b0001&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mb"&gt;0b0010&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mb"&gt;0b0100&lt;/span&gt; &lt;span class="c1"&gt;// 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mb"&gt;0b1000&lt;/span&gt; &lt;span class="c1"&gt;// 8&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;혹은 쉬프트 연산을 활용해서 표현할 수도 있다. 이 방법이 조금 더 직관적이고 단순하다:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;A&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;B&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;C&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이렇게 원소들을 정의하게 되면, 각 원소들이 각각의 자릿수를 점유하고 있기 때문에 겹칠 일이 없다. 따라서 2진수로 쉽게 집합을 표현할 수 있다.&lt;/p&gt;</description></item><item><title>Call by reference와 Call by pointer의 차이</title><link>https://kelly-chui.github.io/posts/cs-programming-language-call-by-reference-call-by-pointer/</link><pubDate>Sat, 07 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-programming-language-call-by-reference-call-by-pointer/</guid><description>&lt;p&gt;Call by reference와 call by pointer는 모두 호출자가 가진 객체를 함수 안에서 변경할 수 있어 비슷해 보인다. 하지만 C++ 언어에서 파라미터가 가지는 의미와 사용할 수 있는 연산은 다르다.&lt;/p&gt;
&lt;h2 id="pointer를-값으로-전달하기"&gt;Pointer를 값으로 전달하기&lt;/h2&gt;
&lt;p&gt;포인터 파라미터는 주소를 저장한 포인터 객체를 값으로 전달받는다. 함수는 복사된 포인터를 역참조해 호출자의 객체를 변경할 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateByPointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;updateByPointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;포인터 자체는 복사본이므로 함수 안에서 다른 주소를 대입해도 호출자가 가진 포인터 변수는 바뀌지 않는다.&lt;/p&gt;</description></item><item><title>SniffMEET. Xcode 프로젝트 파일 정리하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-xcode-project-cleanup/</link><pubDate>Thu, 05 Jun 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-xcode-project-cleanup/</guid><description>&lt;h2 id="작업-내역"&gt;작업 내역&lt;/h2&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/sniffmeet-dev-log-xcode-project-cleanup/image-001-optimized-image.webp"&gt;&lt;p&gt;Xcode에서 프로젝트 파일 관련 경고가 많이 떠서 정리했다.&lt;/p&gt;
&lt;h2 id="작업-내역-1"&gt;작업 내역&lt;/h2&gt;
&lt;h3 id="null-파일-제거"&gt;null 파일 제거&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;320043702CDC9A0D00D08B6D /* (null) in Sources */ = {isa = PBXBuildFile; };
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;320043722CDC9E5F00D08B6D /* (null) in Sources */ = {isa = PBXBuildFile; };
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;320043762CDCA18E00D08B6D /* (null) in Sources */ = {isa = PBXBuildFile; };
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;320043782CDCA49100D08B6D /* (null) in Sources */ = {isa = PBXBuildFile; };
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3200437C2CDCA6F300D08B6D /* (null) in Sources */ = {isa = PBXBuildFile; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이전에 있었던 구조 변경이나, git 충돌/머지 등 다양한 이유로 프로젝트 파일 안에 &lt;code&gt;(null)&lt;/code&gt; 파일을 참조하는 라인이 많이 있었다.&lt;/p&gt;</description></item><item><title>Swift. C부터 시작하는 메소드 디스패치</title><link>https://kelly-chui.github.io/posts/swift-method-dispatch/</link><pubDate>Sat, 31 May 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swift-method-dispatch/</guid><description>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;메소드 호출이란 과연 무엇일까? 우리가 평소에 사용하는 메소드 호출은 내부적으로 어떻게 동작하는지 궁금해진 적이 있다. C++로 PS를 풀 때 가끔 함수 포인터를 써야 하는 경우가 생기는데, Swift에서 클로저를 이용하는 것과 비슷하지만 주변 값을 캡처할 수 없다는 특징이 있다. 함수 포인터는 C에도 존재하는 개념이므로, 다음과 같이 생각이 뻗어나갔다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;함수 포인터와 C 스타일 스트럭처를 사용하면 C언어에서도 OOP 스타일의 메소드가 구현 가능할 것 같다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;생각이 계속 확장되다 보니 실제 OOP 언어의 클래스 구현도 이런 방식으로 되어있지 않을까? 라는 생각에 도달했고, 메소드 디스패치를 포함해서 여러 개념들을 이어서 생각해볼 수 있었다.&lt;/p&gt;</description></item><item><title>OS. Operating System 오버뷰</title><link>https://kelly-chui.github.io/posts/cs-os-overview/</link><pubDate>Sat, 17 May 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-os-overview/</guid><description>&lt;h2 id="운영체제os"&gt;운영체제(OS)&lt;/h2&gt;
&lt;p&gt;컴퓨터 하드웨어와 사용자 사이에서 중간 역할을 수행하며, 하드웨어 자원을 효율적이고 안전하게 관리하고, 사용자 프로그램이 원활하게 실행되도록 지원하는 시스템 소프트웨어&lt;/p&gt;
&lt;h3 id="커널"&gt;커널&lt;/h3&gt;
&lt;p&gt;운영체제의 핵심 부분, 하드웨어와 직접 상호작용 하여, 자원 관리와 시스템 콜 처리를 담당하는 코드 영역, 일반적으로 운영체제는 커널을 지칭한다.&lt;/p&gt;
&lt;h2 id="역할"&gt;역할&lt;/h2&gt;
&lt;p&gt;운영체제는 CPU, 메모리 등의 하드웨어를 효율적으로 사용할 수 있도록 관리하고, 애플리케이션이 자원을 효율적으로 할당받아 문제 없이 실행될 수 있도록 한다.&lt;/p&gt;
&lt;h3 id="cpu-관리cpu-스케줄링"&gt;CPU 관리(CPU 스케줄링)&lt;/h3&gt;
&lt;p&gt;CPU가 실행 중인 프로그램을 모두 동시에 실행할 수 있는 것은 아니므로, 프로그램들이 효율적으로 CPU를 할당받도록 할당 순서와 사용 시간을 결정하는 역할&lt;/p&gt;</description></item><item><title>DB. Database 오버뷰.</title><link>https://kelly-chui.github.io/posts/cs-db-overview/</link><pubDate>Sat, 03 May 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-db-overview/</guid><description>&lt;h2 id="데이터베이스database-db"&gt;데이터베이스(Database, DB)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;여러 사람이 공동으로 사용하기 위해 통합, 저장하여 운영하는 데이터들의 집합&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;특정 조직(서비스)의 업무를 수행하는데 필요한 상호 관련된 데이터들의 모임이다.&lt;/p&gt;
&lt;h3 id="dbmsdatabase-management-system"&gt;DBMS(Database Management System)&lt;/h3&gt;
&lt;p&gt;데이터베이스를 관리하기 위한 프로그램, 대표적으로 SQL을 사용하는 관계형 데이터베이스(RDBMS)가 있고, SQL을 사용하지 않는 NoSQL DBMS도 있다.&lt;/p&gt;
&lt;h2 id="관계형-데이터베이스relational-db-rdb"&gt;관계형 데이터베이스(Relational DB, RDB)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;2차원 표를 이용해서 데이터간의 상호 관계를 정의하는 데이터베이스&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="스키마schema"&gt;스키마(Schema)&lt;/h3&gt;
&lt;p&gt;데이터베이스의 구조와 제약 조건에 대한 전반적인 명세. 엔티티, 어트리뷰트, 릴레이션, 제약 조건 등을 전반적으로 정의한 DB의 구조적 정의&lt;/p&gt;</description></item><item><title>BOJ 12852. 1로 만들기 2</title><link>https://kelly-chui.github.io/ps/2025/ps-boj-12852-make-one-2/</link><pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-boj-12852-make-one-2/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/12852"&gt;https://www.acmicpc.net/problem/12852&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DP를 사용해서 해결했다.&lt;/p&gt;
&lt;p&gt;문제를 거꾸로 뒤집어보자. n에서 1을 가는 최단거리가 아니라, 1에서 n으로 가는 최단거리로 바꾸는 편이 편하다.&lt;/p&gt;
&lt;p&gt;이렇게 뒤집으면 개별 숫자에서 다른 숫자로 갈 수 있는 방법은 3가지가 주어진다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 더하기&lt;/li&gt;
&lt;li&gt;2 곱하기&lt;/li&gt;
&lt;li&gt;3 곱하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;쉽게 점화식을 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;dp[i] = max(dp[i - 1], dp[i / 2], dp[i / 3]) + 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;하지만 경로도 트래킹 해야 하는데, 이건 각 개별 숫자에 도달하기 전에 어떤 수에서 왔는지를 저장하는 배열 하나를 만들고, 최종적으로 이 배열을 루프로 순회하거나, 재귀를 통해서 경로를 얻어낼 수 있다.&lt;/p&gt;</description></item><item><title>BOJ 2193. 이친수</title><link>https://kelly-chui.github.io/ps/2025/ps-boj-2193-pinary-number/</link><pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-boj-2193-pinary-number/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2193"&gt;https://www.acmicpc.net/problem/2193&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제에서 명시적으로 두 가지 조건을 제공해준다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;0으로 시작하지 않는다.&lt;/li&gt;
&lt;li&gt;1이 연속되지 않는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이진수라는 조건도 있으므로, 3가지 조건이 있다고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;케이스를 몇개 써보면 쉽게 DP로 풀 수 있는걸 알 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// 10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;// 100, 101&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;// 1000, 1001, 1010&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2번째 조건 때문에, 0으로 끝나는 경우에는 1을 붙일 수 있지만, 1로 끝나는 경우에는 0으로 붙일 수 없는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;DP 테이블을 다음과 같이 정의하자.&lt;/p&gt;</description></item><item><title>Algorithm. LIS(Subsequence)</title><link>https://kelly-chui.github.io/posts/cs-algorithm-lis-subsequence/</link><pubDate>Thu, 03 Apr 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-algorithm-lis-subsequence/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;수열의 원소를 골라내서 만든 부분 수열 중, 각 원소가 이전 원소보다 크면서, 가장 긴 길이를 가지는 부분 수열을 찾는 알고리즘&lt;/p&gt;
&lt;p&gt;DP 방식과 Binary Search를 쓰는 Greedy 방식 두 가지가 있으며, 별개의 방식이 아닌 두 방식이 밀접하게 연관되어 있다.&lt;/p&gt;
&lt;h2 id="아이디어"&gt;아이디어&lt;/h2&gt;
&lt;p&gt;LIS는 현재까지 구한 부분 수열의 결과를 이용해 더 긴 부분 수열을 만들어 나가는 문제이다.&lt;/p&gt;
&lt;p&gt;DP는 이전 계산 결과를 이용해 현재 상태를 구하며, Binary Search를 이용한 방식은 같은 아이디어를 유지하면서 탐색 과정을 최적화한 것이다.&lt;/p&gt;</description></item><item><title>Software Engineering. DI와 DIP</title><link>https://kelly-chui.github.io/posts/se-dependency-injection/</link><pubDate>Thu, 27 Mar 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/se-dependency-injection/</guid><description>&lt;h2 id="의존성-주입dependency-injection"&gt;의존성 주입(Dependency Injection)&lt;/h2&gt;
&lt;p&gt;의존성 주입은 객체가 필요한 의존성을 내부에서 직접 생성하지 않고 외부에서 전달받는 방식이다. 별도의 DI 프레임워크나 주입 전용 객체가 반드시 필요한 것은 아니다. 생성자를 통해 객체를 전달하는 것만으로도 의존성 주입이 된다.&lt;/p&gt;
&lt;h2 id="의존의-의미"&gt;의존의 의미&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;A → B&lt;/code&gt;: &lt;code&gt;A&lt;/code&gt;가 &lt;code&gt;B&lt;/code&gt;에 의존한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;A&lt;/code&gt;가 동작하기 위해 &lt;code&gt;B&lt;/code&gt;의 타입이나 기능을 사용한다면 &lt;code&gt;A&lt;/code&gt;는 &lt;code&gt;B&lt;/code&gt;에 의존한다. &lt;code&gt;B&lt;/code&gt;의 공개 인터페이스가 바뀌면 &lt;code&gt;A&lt;/code&gt;도 영향을 받을 수 있다.&lt;/p&gt;
&lt;p&gt;다음 코드에서 &lt;code&gt;Greeter&lt;/code&gt;는 구체 타입인 &lt;code&gt;EnglishGreetingProvider&lt;/code&gt;를 직접 생성한다.&lt;/p&gt;
&lt;img alt="Screenshot 2024-09-29 at 4.21.47\u202fPM.png" loading="lazy" src="https://kelly-chui.github.io/posts/se-dependency-injection/image-001-optimized-image.webp"&gt;&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EnglishGreetingProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;EnglishGreetingProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 구조에서는 구현을 교체하거나 테스트 대역을 사용하려면 &lt;code&gt;Greeter&lt;/code&gt;를 직접 수정해야 한다.&lt;/p&gt;</description></item><item><title>Network. VPN(Virtual Private Network)</title><link>https://kelly-chui.github.io/posts/cs-network-vpn/</link><pubDate>Tue, 04 Mar 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-vpn/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;VPN은 공용 네트워크를 이용하여 사설 네트워크처럼 안전하게 통신할 수 있도록 하는 기술이다.&lt;/p&gt;
&lt;p&gt;공용 네트워크를 통해 사설 네트워크처럼 안전하게 데이터를 주고받는 기술, 데이터를 암호화하여 외부로부터의 도청, 해킹, 감시로부터 보호하고, 원격으로 사설 네트워크에 안전하게 접속할 수 있도록 한다.&lt;/p&gt;
&lt;h2 id="동작-원리"&gt;동작 원리&lt;/h2&gt;
&lt;h3 id="암호화"&gt;암호화&lt;/h3&gt;
&lt;p&gt;사용자의 데이터를 암호화 하여 전송하므로, ISP나 외부에서 데이터를 읽을 수 없도록 한다.&lt;/p&gt;
&lt;h3 id="터널링"&gt;터널링&lt;/h3&gt;
&lt;p&gt;VPN 터널이라는 보안 통로를 통해 전송됨, 데이터 패킷을 감싸 보호하는 역할을 한다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;대표적인 VPN 프로토콜: OpenVPN, IPsec, WireGuard&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ip-주소-변경"&gt;IP 주소 변경&lt;/h3&gt;
&lt;p&gt;VPN 서버를 통해 인터넷에 접속하면 목적지 서버에는 사용자의 공인 IP 대신 VPN 서버의 IP가 보인다. 하지만 VPN 사업자는 사용자의 원래 IP와 트래픽 정보를 볼 수 있고, 쿠키나 계정 같은 다른 식별 수단도 남으므로 VPN이 익명성을 보장하는 것은 아니다.&lt;/p&gt;</description></item><item><title>SniffMEET. 닉네임 검증 개선 고민</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-nickname-validation-combine/</link><pubDate>Thu, 13 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-nickname-validation-combine/</guid><description>&lt;h2 id="작업-내역"&gt;작업 내역&lt;/h2&gt;
&lt;p&gt;닉네임 TextField의 검증 방식을 다시 정리했다. 현재는 &lt;code&gt;UITextFieldDelegate&lt;/code&gt;로 길이 검증과 버튼 활성화를 처리하고 있었는데, 중복 체크까지 같은 흐름에 넣을 경우 네트워크 요청이 너무 자주 발생할 수 있어 보였다.&lt;/p&gt;
&lt;h3 id="현재-구현"&gt;현재 구현&lt;/h3&gt;
&lt;p&gt;현재는 Delegate 기반으로 다음 두 가지를 처리하고 있었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;ProfileCreateViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITextFieldDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;textFieldDidChangeSelection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;textField&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITextField&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;textCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;textField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;submitButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textCount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;textCount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;textField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;textField&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITextField&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;shouldChangeCharactersIn&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NSRange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;replacementString&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;textField&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;newLength&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;inputTextValid&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newLength&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inputTextValid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;길이 검증 자체는 단순했고, 현재 사용성도 나쁘지 않았다.&lt;/p&gt;
&lt;p&gt;문제는 중복 체크처럼 네트워크 요청이 들어가는 검증까지 같은 방식으로 처리하기에는 부담이 커진다는 점이었다.&lt;/p&gt;</description></item><item><title>SniffMEET. AuthManager와 SessionManager의 책임 분리하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-auth-session-responsibilities/</link><pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-auth-session-responsibilities/</guid><description>&lt;h2 id="작업-배경"&gt;작업 배경&lt;/h2&gt;
&lt;p&gt;AuthManager와 SessionManager는 서로 매우 밀접하게 연관된 작업을 한다. AuthManager는 사용자의 계정 인증을 담당하고 세션을 받아오며, SessionManager는 그 세션을 관리한다.&lt;/p&gt;
&lt;p&gt;하지만 기존 코드에서는 세션 관리를 포함한 대부분의 작업을 &lt;code&gt;AuthManager&lt;/code&gt;가 처리하고, &lt;code&gt;SessionManager&lt;/code&gt;는 세션을 소유하는 역할만 하고 있었다.&lt;/p&gt;
&lt;h3 id="역할-분리"&gt;역할 분리&lt;/h3&gt;
&lt;p&gt;기존에는 &lt;code&gt;AuthManager&lt;/code&gt;에서 세션 갱신, 복원, 저장, 로드 작업을 처리하고 있었고, &lt;code&gt;SessionManager&lt;/code&gt;는 세션의 만료 여부 확인과 세션 객체를 소유하는 역할만 맡고 있었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// AuthManager 인터페이스 프로토콜&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;AuthManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AuthManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;authStateSubject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PassthroughSubject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AuthState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Never&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;get&lt;/span&gt; &lt;span class="kr"&gt;set&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;signInAnonymously&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;restoreSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;refreshSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;loadTokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// SessionManager 클래스&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SessionManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SupabaseSession&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isExpired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 세션 만료를 파악할 때는 30초의 여유시간을 줍니다.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeIntervalSince1970&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;그래서 세션 관리는 &lt;code&gt;SessionManager&lt;/code&gt;, 인증은 &lt;code&gt;AuthManager&lt;/code&gt;가 맡도록 기능을 다시 정의했다.&lt;/p&gt;</description></item><item><title>SniffMEET. Interactor가 인프라를 직접 알아도 될까</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-interactor-infrastructure-dependency/</link><pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-interactor-infrastructure-dependency/</guid><description>&lt;h2 id="interactor에서-직접-매니저-호출하지-않기"&gt;Interactor에서 직접 매니저 호출하지 않기&lt;/h2&gt;
&lt;p&gt;매니저가 변하면 인터랙터를 직접 변경해야한다. 매니저와 인터랙터 간의 의존성을 줄이고, 인터랙터는 “비즈니스 로직”만, 그리고 비즈니스 로직의 구현체인 유즈케이스에서 네트워크 요청이나 데이터 관리와 같은 인프라 로직을 담당하는 것이 좋다고 생각한다.&lt;/p&gt;
&lt;p&gt;또한 싱글톤 객체여도 현재 주입하는 방식으로 사용중인데, 인터랙터에서 사용하면 직접 매니저의 싱글톤 객체를 호출해서 사용해야 한다:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sendWalkRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;latitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;longtitude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;myInfo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;loadUserInfoUseCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;requestWalkUseCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;walkNoti&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;walkNoti&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;didSendWalkRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;위 코드에서 &lt;code&gt;id&lt;/code&gt;를 얻기 위해 SessionManager의 싱글톤 객체를 호출해야 한다. 싱글톤 객체 호출 자체는 크게 문제가 되지 않을 수 있지만, 다음과 같이 생각해볼 주제가 있다.&lt;/p&gt;</description></item><item><title>SniffMEET. 세션 갱신과 정보 접근을 SessionManager에 캡슐화하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-session-manager-encapsulation/</link><pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-session-manager-encapsulation/</guid><description>&lt;h2 id="sessionmanager-사용성-개선"&gt;SessionManager 사용성 개선&lt;/h2&gt;
&lt;h3 id="세션을-갱신하는-방법"&gt;세션을 갱신하는 방법&lt;/h3&gt;
&lt;p&gt;Supabase 서버와의 통신이 필요할 때, 우선 세션의 유효성을 검증해야 한다.&lt;/p&gt;
&lt;p&gt;기존 방식에선 직접 AuthManager의 싱글톤 객체에서 세션을 갱신하는 작업을 했지만&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AuthManager와 SessionManager의 역할 명확하게 분리&lt;/li&gt;
&lt;li&gt;AuthManager의 싱글톤 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;와 같은 변화점이 있었고, 기존 AuthManager가 담당하던 세션 갱신, 복원 작업이 SessionManager로 옮겨졌다. SessionManager의 싱글톤 객체에서 세션의 유효성을 체크하는 컴퓨티드 프로퍼티의 부울리언 값을 체크하여 세션을 갱신하는 메소드를 호출하는 방식을 사용했다:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isExpired&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SessionManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refreshSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 방식은 SessionManager의 싱글톤 객체 호출이 두 번 일어나고, &lt;code&gt;refreshSession&lt;/code&gt;이라는 메소드를 직접 노출해서, SessionManager가 세션을 갱신하는 방법을 직접 노출하는 문제가 있다.&lt;/p&gt;</description></item><item><title>SniffMEET. 세션 저장 메소드를 공개해도 괜찮을까?</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-session-save-api/</link><pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-session-save-api/</guid><description>&lt;h2 id="세션-저장하기"&gt;세션 저장하기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;AuthManager&lt;/code&gt;와 &lt;code&gt;SessionManager&lt;/code&gt;의 역할을 분리하고 나니, 세션을 받아오는 쪽과 저장하는 쪽이 서로 달라지는 문제가 발생했다.&lt;/p&gt;
&lt;p&gt;(AuthManager가 세션도 관리하던)기존 구조에서는 &lt;code&gt;saveSession(for:)&lt;/code&gt;가 외부에 노출되어 있지 않았는데, 역할이 옮겨진 뒤에는 AuthManager에서 받아온 세션을 SessionManager로 전달해야 했다.&lt;/p&gt;
&lt;h3 id="고민한-점"&gt;고민한 점&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;saveSession(for:)&lt;/code&gt;는 사실상 &lt;code&gt;AuthManager&lt;/code&gt;가 세션을 받아온 상황에서만 필요한 메소드다.&lt;/p&gt;
&lt;p&gt;그런데 이 메소드를 공개하면 캡슐화가 약해진다는 생각을 했고, 다시 AuthManager로 돌리면 SessionManager가 맡아야 할 책임을 되돌리는 것이 되었다.&lt;/p&gt;
&lt;p&gt;따라서 몇 가지 방법을 떠올려 봤다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;(최종 선택) &lt;code&gt;saveSession(for:)&lt;/code&gt;를 공개한다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;saveSession(for:)&lt;/code&gt;를 &lt;code&gt;AuthManager&lt;/code&gt;로 다시 옮긴다&lt;/li&gt;
&lt;li&gt;같은 로직을 &lt;code&gt;AuthManager&lt;/code&gt;와 &lt;code&gt;SessionManager&lt;/code&gt;에 각각 작성한다&lt;/li&gt;
&lt;li&gt;세션이 갱신됐다는 이벤트를 따로 전달할 수 있는 통신 레이어를 만든다&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;처음에 가장 괜찮아 보였던 건 세션 갱신 이벤트를 따로 전달하는 방식이었다.&lt;/p&gt;</description></item><item><title>Swift. 프로토콜 요구사항과 메소드 어트리뷰트</title><link>https://kelly-chui.github.io/posts/swift-discardable-result-protocol-requirement/</link><pubDate>Mon, 10 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swift-discardable-result-protocol-requirement/</guid><description>&lt;p&gt;&lt;code&gt;RemoteDBRequestBuildable&lt;/code&gt; 프로토콜을 추가한 뒤, 이전에는 나타나지 않던 unused-result 경고가 발생했다.&lt;/p&gt;
&lt;img alt="프로토콜을 통한 호출에서 발생한 unused-result 경고" loading="lazy" src="https://kelly-chui.github.io/posts/swift-discardable-result-protocol-requirement/image-001-optimized-image.webp"&gt;&lt;h2 id="구체-타입에서는-사라졌던-경고"&gt;구체 타입에서는 사라졌던 경고&lt;/h2&gt;
&lt;p&gt;기존 구현의 &lt;code&gt;request()&lt;/code&gt;에는 &lt;code&gt;@discardableResult&lt;/code&gt;가 붙어 있었다. 반환값을 사용하지 않아도 경고가 발생하지 않았다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupabaseDBRequestBuilder&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;discardableResult&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;concrete&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SupabaseDBRequestBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;concrete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이후 Builder를 프로토콜로 추상화했지만 프로토콜 요구사항에는 해당 어트리뷰트를 붙이지 않았다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;RemoteDBRequestBuildable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="kr"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;SupabaseDBRequestBuilder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RemoteDBRequestBuildable&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;abstract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="n"&gt;RemoteDBRequestBuildable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SupabaseDBRequestBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;abstract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;구체 구현에는 여전히 &lt;code&gt;@discardableResult&lt;/code&gt;가 있는데도, 프로토콜 타입으로 호출하면 경고가 다시 나타났다.&lt;/p&gt;
&lt;h2 id="호출을-검사하는-선언과-실행할-구현"&gt;호출을 검사하는 선언과 실행할 구현&lt;/h2&gt;
&lt;p&gt;컴파일러는 호출 지점의 정적 타입을 기준으로 사용할 메서드 선언을 해석한다.&lt;/p&gt;</description></item><item><title>SniffMEET. ISP로 Supabase 요청 빌더 역할 나누기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-request-interface-segregation/</link><pubDate>Thu, 06 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-request-interface-segregation/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;Supabase REST API를 직접 감싸서 사용하다 보니, 유즈케이스 레이어에서 &lt;code&gt;eq.&lt;/code&gt;, &lt;code&gt;in.&lt;/code&gt;, &lt;code&gt;gte.&lt;/code&gt; 같은 쿼리 문자열을 직접 조립하는 코드가 늘어났다.&lt;/p&gt;
&lt;p&gt;처음에는 단순했지만, 요청이 많아질수록 오타 가능성이 커지고 Supabase의 세부 문법이 상위 레이어로 새어 나오는 문제가 있었다. 이번 글은 이 쿼리 구성 책임을 Supabase DB Layer 안으로 옮기기 위해 요청 빌더와 쿼리 파라미터 래퍼를 도입한 과정을 정리한다.&lt;/p&gt;
&lt;h2 id="기본-구조"&gt;기본 구조&lt;/h2&gt;
&lt;p&gt;SNMNetwork의 동작을 간단하게 설명하면, &lt;code&gt;SNMRequestConvertible&lt;/code&gt;을 채택하는 객체의 정보로 네트워크 요청을 생성하고, 통신한 다음, 응답을 반환하는 방식으로 동작한다.&lt;/p&gt;</description></item><item><title>Network. NAT(Network Address Translation)</title><link>https://kelly-chui.github.io/posts/cs-network-nat/</link><pubDate>Wed, 05 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-nat/</guid><description>&lt;h2 id="nat"&gt;NAT&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;NAT: Network Address Translation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;패킷이 라우팅 장치를 통해 전송되는 동안 패킷의 IP 주소 정보를 수정하여 IP 주소를 다른 주소로 매핑하는 방법, 공인 IP와 사설 IP로 나눠서 처리한다.&lt;/p&gt;
&lt;h2 id="동작-원리"&gt;동작 원리&lt;/h2&gt;
&lt;img alt="Untitled.png" loading="lazy" src="https://kelly-chui.github.io/posts/cs-network-nat/image-001-optimized-image.webp"&gt;&lt;p&gt;NAT는 라우터에서 동작하며, 내부 네트워크의 사설 IP 주소를 외부에서 사용할 수 있는 공인 IP 주소로 변환한다. 이를 통해 여러 장치가 하나의 공인 IP 주소를 공유하면서 인터넷에 접속할 수 있다.&lt;/p&gt;
&lt;h3 id="동작-방식"&gt;동작 방식&lt;/h3&gt;
&lt;h4 id="출발지-주소-변환-snat-source-nat"&gt;출발지 주소 변환 (SNAT: Source NAT)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;내부 네트워크의 컴퓨터가 외부에 패킷을 전송할 때 사설 IP주소를 공인 IP주소로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="목적지-주소-변환-dnat-destination-nat"&gt;목적지 주소 변환 (DNAT: Destination NAT)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;외부에서 내부로 네트워크로 들어오는 패킷의 목적지 IP를 공인 IP에서 내부 네트워크의 사설 IP로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="포트-주소-변환-pat-port-address-translation"&gt;포트 주소 변환 (PAT: Port Address Translation)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;여러 내부 IP들이 하나의 공인 IP를 공유하기 때문에, 포트 번호로 이들을 구별한다.&lt;/li&gt;
&lt;li&gt;하나의 공인 IP 주소를 여러 장치가 함께 사용할 수 있도록 포트 번호를 함께 변환하여 구분한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어 다음과 같이 서로 다른 내부 장치가 하나의 공인 IP를 사용할 수 있다.&lt;/p&gt;</description></item><item><title>Network. 쿠키, 세션</title><link>https://kelly-chui.github.io/posts/cs-network-cookie-session/</link><pubDate>Sun, 02 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-cookie-session/</guid><description>&lt;h2 id="개요"&gt;개요&lt;/h2&gt;
&lt;p&gt;웹 애플리케이션에서 사용자 정보를 저장하고 관리하는 방식, HTTP는 statelessness이기 때문에, 이전 요청에 대한 정보를 기억하지 않는다. 따라서 이 문제를 해결하기 위해 쿠키와 세션이 필요하다.&lt;/p&gt;
&lt;h2 id="쿠키"&gt;쿠키&lt;/h2&gt;
&lt;p&gt;클라이언트에 저장되는 작은 데이터 파일, 서버가 클라이언트에게 데이터를 저장하도록 지시하면, 해당 데이터를 전송하게 됨&lt;/p&gt;
&lt;h3 id="용도"&gt;용도&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;사용자 인증 정보 저장 (로그인 상태 유지)&lt;/li&gt;
&lt;li&gt;웹사이트 설정 저장&lt;/li&gt;
&lt;li&gt;사용자 행동 추적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="특징"&gt;특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;주기적 전송: 사용자가 특정 사이트에 다시 방문하면 브라우저가 자동으로 쿠키를 서버로 전송함&lt;/li&gt;
&lt;li&gt;수명: 유효 기간을 설정할 수 있고, 만료되면 삭제됨, 유효기간이 없으면 브라우저 세션이 종료될 때 삭제&lt;/li&gt;
&lt;li&gt;용량: 한 도메인당 쿠키는 4KB 정도로 제한&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="보안"&gt;보안&lt;/h3&gt;
&lt;p&gt;사용자의 브라우저에 저장되기 때문에 클라이언트에서 조작할 수 있다. 따라서 민감한 데이터는 쿠키에 저장하면 안됨&lt;/p&gt;</description></item><item><title>OS. Stack, Heap 메모리 관리</title><link>https://kelly-chui.github.io/posts/cs-os-stack-and-heap/</link><pubDate>Sun, 02 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-os-stack-and-heap/</guid><description>&lt;p&gt;Date: February 2, 2025
Multi-select: Memory&lt;/p&gt;
&lt;h2 id="스택-메모리"&gt;스택 메모리&lt;/h2&gt;
&lt;p&gt;LIFO 구조로, 함수 호출 시 생성되는 스택 프레임(로컬 변수, 파라미터, 반환 주소 등)을 저장한다. 함수가 호출 될 때 마다 새로운 스택 프레임이 쌓이고, 함수가 종료되면 스택 프레임 제거된다.&lt;/p&gt;
&lt;h3 id="특징"&gt;특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;빠른 메모리 할당/해제: 스택은 메모리가 자동으로 관리되어서 함수가 끝나면 알아서 메모리가 반환됨&lt;/li&gt;
&lt;li&gt;고정 크기: 스택 메모리는 크기가 제한적이라서 너무 많은 데이터를 저장하면 스택 오버플로우 위험이 있음&lt;/li&gt;
&lt;li&gt;호출 상태 저장: 함수의 매개변수와 지역 값 일부가 스택 프레임에 저장될 수 있음. 실제 저장 위치는 ABI와 컴파일러 최적화에 따라 레지스터나 다른 영역이 될 수도 있음&lt;/li&gt;
&lt;li&gt;스레드별 스택: 각 스레드는 별도의 호출 스택을 가지지만, 이것만으로 함수나 데이터 전체가 thread-safe해지는 것은 아님. 스택에 있는 참조가 공유 객체를 가리킬 수도 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="스택-오버플로우"&gt;스택 오버플로우&lt;/h3&gt;
&lt;p&gt;프로그램이 스택 메모리를 초과할 때 발생하는 오류, 함수 호출 시마다 생성되는 스택 프레임이 쌓이면서 스택 공간을 사용하게 되고, 이 제한된 스택 공간을 초과해서 스택 프레임이 쌓일 경우 발생한다.&lt;/p&gt;</description></item><item><title>Network. ARP(Address Resolution Protocol)</title><link>https://kelly-chui.github.io/posts/cs-network-arp/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-arp/</guid><description>&lt;h2 id="arp"&gt;ARP&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;ARP: Address Resolution Protocol&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;네트워크에서 IP 주소와 MAC 주소를 변환하는 프로토콜&lt;/p&gt;
&lt;h2 id="동작-방식"&gt;동작 방식&lt;/h2&gt;
&lt;p&gt;데이터 전송 시, 송신자는 목적지의 MAC 주소를 알아야 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;송신 장치가 ARP Request를 브로드캐스트한다.
&lt;ul&gt;
&lt;li&gt;여기서 네트워크의 범위는 LAN, 즉 서브넷 내부&lt;/li&gt;
&lt;li&gt;서브넷 마스크를 이용해서 공유기를 거쳐야 하는지 판단함.&lt;/li&gt;
&lt;li&gt;이때 기본 게이트웨이는 이미 알고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;해당 IP 주소를 가진 장치가 ARP Reply를 유니캐스트로 응답한다.&lt;/li&gt;
&lt;li&gt;이 정보를 ARP 캐시에 저장하여 다음 통신에서 요청하지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note.&lt;/p&gt;
&lt;p&gt;ARP 캐시: IP 주소와 MAC 주소의 대응 관계를 임시로 저장한 캐시 메모리&lt;/p&gt;</description></item><item><title>Network. DHCP(Dynamic Host Configuration Protocol)</title><link>https://kelly-chui.github.io/posts/cs-network-dhcp/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-dhcp/</guid><description>&lt;h2 id="개요"&gt;개요&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;DHCP: Dynamic Host Configuration Protocol&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;디바이스가 네트워크에 접속하려면 고유한 IP주소가 필요하지만, 수동으로 설정하면 불편하고 충돌이 발생할 가능성이 있음, DHCP 서버는 자동으로 IP 주소와 서브넷 마스크, 게이트웨이와 같은 파라미터를 배정한다.&lt;/p&gt;
&lt;h2 id="동작-방식"&gt;동작 방식&lt;/h2&gt;
&lt;h3 id="dora"&gt;DORA&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Discovery
&lt;ul&gt;
&lt;li&gt;클라이언트가 네트워크에 연결되면, IP 주소가 필요하다고 브로드 캐스트 요청을 보냄&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Offer
&lt;ul&gt;
&lt;li&gt;DHCP 서버가 사용 가능한 IP 주소를 찾아서 클라이언트에게 제안&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Request
&lt;ul&gt;
&lt;li&gt;클라이언트가 서버에게 응답함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Acknowledge
&lt;ul&gt;
&lt;li&gt;DHCP 서버가 설정을 최종적으로 승인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="임대"&gt;임대&lt;/h3&gt;
&lt;p&gt;DHCP는 IP 주소를 영구적으로 할당하지 않고 일정 시간 동안 임대(Lease)하는 방식으로 관리한다.&lt;/p&gt;</description></item><item><title>Network. DNS(Domain Name System)</title><link>https://kelly-chui.github.io/posts/cs-network-dns/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-dns/</guid><description>&lt;h2 id="dns"&gt;DNS&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;DNS: Domain Name System&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;도메인 이름을 IP 주소로 변환하는 시스템, 웹 사이트 주소를 IP주소로 변환해주는 역할&lt;/p&gt;
&lt;h2 id="동작-방식"&gt;동작 방식&lt;/h2&gt;
&lt;p&gt;DNS는 계층 구조를 가지며, 요청을 처리하는 과정에서 필요한 DNS 서버를 순차적으로 탐색한다. 한 번 조회한 결과는 캐시에 저장되어 이후에는 같은 과정을 반복하지 않을 수 있다.&lt;/p&gt;
&lt;p&gt;사용자가 google.com을 입력했다고 하면, 맥이 자동으로 로컬 DNS 서버에 요청을 보냄 → 만약 로컬 DNS 서버가 정보를 가지고 있지 않다면, 상위 DNS 서버로 요청을 보냄&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1. 맥 → 로컬 캐시 확인
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2. 로컬 DNS 서버(ISP DNS 서버) → 로컬 캐시 확인
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3. 로컬 DNS 서버 → 재귀 DNS 서버에 요청
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;4. 재귀 DNS 서버 → 루트 DNS 서버 → TLD DNS 서버 → 권한 있는 네임서버
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5. 권한 있는 네임서버 → IP 주소 반환
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6. 재귀 DNS 서버 → 로컬 DNS 서버 → IP 주소 전달
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;7. 로컬 DNS 서버 → 맥에 최종 IP 주소 전달
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;8. 맥 → 구글 접속&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;재귀 DNS 서버(Recursive DNS Server)는 클라이언트를 대신하여 필요한 DNS 서버를 차례대로 조회하고 최종 결과를 반환하는 역할을 한다.&lt;/p&gt;</description></item><item><title>Network. Load Balancing</title><link>https://kelly-chui.github.io/posts/cs-network-load-balancing/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-load-balancing/</guid><description>&lt;h2 id="로드-밸런싱"&gt;로드 밸런싱&lt;/h2&gt;
&lt;p&gt;가용성, 성능, 확장성을 높이기 위해 여러 서버에 네트워크 트래픽을 분산하는 방법이다.&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;p&gt;서버와 클라이언트 간의 트래픽을 지시하고 제어하여 가용성, 확장성, 보안 및 성능이 향상됨&lt;/p&gt;
&lt;h3 id="가용성"&gt;가용성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;여러 서버에 트래픽을 분배하여 한 서버가 다운되었을 때, 사용 가능한 서버로 트래픽을 리다이렉션한다.&lt;/li&gt;
&lt;li&gt;애플리케이션 가동 중지 없이 서버 유지 관리 및 업그레이드 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="성능"&gt;성능&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;여러 서버에 요청을 분배하여, 네트워크 지연 시간을 줄임&lt;/li&gt;
&lt;li&gt;물리적으로 더 가까운 서버로 리다이렉션 하여 지연 시간 단축&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="보안"&gt;보안&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;트래픽 모니터링&lt;/li&gt;
&lt;li&gt;공격 트래픽을 여러 서버로 리다이렉션 하여 영향 최소화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="확장성"&gt;확장성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;서버 수를 동적으로 추가하거나 제거하여 트래픽 변화에 유연하게 대응 가능&lt;/li&gt;
&lt;li&gt;수평 확장(서버 추가), 수직 확장(성능 향상) 둘 다 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="동작-원리"&gt;동작 원리&lt;/h2&gt;
&lt;h3 id="l4-로드-밸런싱"&gt;L4 로드 밸런싱&lt;/h3&gt;
&lt;p&gt;전송 계층에서 수행하는 로드 밸런싱, 패킷 헤더에 포함된 정보를 기반으로 TCP나 UDP 패킷을 기준으로 트래픽을 분배한다.&lt;/p&gt;</description></item><item><title>Network. REST(Representational State Transfer)</title><link>https://kelly-chui.github.io/posts/cs-network-restful-api/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-restful-api/</guid><description>&lt;h2 id="rest"&gt;REST&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;REST: Representational State Transfer&lt;/li&gt;
&lt;li&gt;RESTful API: REST를 기반으로 한 API&lt;/li&gt;
&lt;li&gt;REST 아키텍처 스타일의 설계 원칙을 준수하는 API&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Note.&lt;/p&gt;
&lt;p&gt;REST는 HTTP와 동일한 개념이 아니다. REST는 웹 API를 설계하기 위한 아키텍처 스타일이며, HTTP는 REST를 구현할 때 가장 많이 사용하는 프로토콜이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="설계-원칙"&gt;설계 원칙&lt;/h2&gt;
&lt;h3 id="uniform-interface"&gt;Uniform interface&lt;/h3&gt;
&lt;p&gt;동일한 리소스에 대한 모든 API 요청은 동일하게 표시되어야 한다(리소스는 단일 URL을 통해 식별할 수 있도록 고유해야 한다). 서버는 표준 형식으로 정보를 전송하고, 형식이 지정된 리소스를 REST에서는 표현(Represent)라고 한다.&lt;/p&gt;</description></item><item><title>Network. 프록시</title><link>https://kelly-chui.github.io/posts/cs-network-proxy/</link><pubDate>Sat, 01 Feb 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-proxy/</guid><description>&lt;h2 id="프록시"&gt;프록시&lt;/h2&gt;
&lt;img alt="proxy.png" loading="lazy" src="https://kelly-chui.github.io/posts/cs-network-proxy/image-001-optimized-image.webp"&gt;&lt;p&gt;클라이언트와 서버 사이에 중간 역할을 하는 시스템, 클라이언트의 요청을 대신 처리하고 서버로부터 받은 응답을 클라이언트에 전달하는 방식으로 작동&lt;/p&gt;
&lt;p&gt;프록시는 클라이언트와 서버 사이에서 요청과 응답을 대신 전달하는 중개 서버이다.&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;h3 id="익명성-제공"&gt;익명성 제공&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;클라이언트의 실제 IP 주소를 숨기고, 프록시 서버의 IP 주소 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="캐싱"&gt;캐싱&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;자주 요청되는 데이터를 미리 저장해두고, 클라이언트의 요청이 있을 떄 빠르게 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="보안"&gt;보안&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;프록시 서버는 클라이언트와 서버 사이에 존재, 보안 및 필터링 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="트래픽-제어"&gt;트래픽 제어&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;리소스 보호를 위해 트래픽 필터링&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="종류"&gt;종류&lt;/h2&gt;
&lt;h3 id="포워드-프록시"&gt;포워드 프록시&lt;/h3&gt;
&lt;p&gt;클라이언트가 외부 서버에 접근할 때 중개 역할을 하는 프록시&lt;/p&gt;</description></item><item><title>Network. TCP Flow &amp; Congestion Control</title><link>https://kelly-chui.github.io/posts/cs-network-tcp-flow-congestion-control/</link><pubDate>Fri, 31 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-tcp-flow-congestion-control/</guid><description>&lt;h2 id="개요"&gt;개요&lt;/h2&gt;
&lt;p&gt;TCP는 신뢰성 있는 데이터 전송을 위해 흐름 제어(Flow Control) 와 혼잡 제어(Congestion Control) 기능을 제공함.&lt;/p&gt;
&lt;p&gt;흐름 제어는 송신자와 수신자 사이의 데이터 전송량을 조절하고, 혼잡 제어는 네트워크 전체의 혼잡을 방지하기 위한 메커니즘이다.&lt;/p&gt;
&lt;h2 id="흐름-제어-flow-control"&gt;흐름 제어 (Flow Control)&lt;/h2&gt;
&lt;p&gt;송신자와 수신자의 처리 속도 차이로 인해 데이터가 손실되지 않도록 전송량을 조절하는 기능이다.&lt;/p&gt;
&lt;h3 id="정지-대기-stop-and-wait"&gt;정지-대기 (Stop-and-Wait)&lt;/h3&gt;
&lt;p&gt;수신 측의 ACK를 받은 후에 다음 패킷을 전송하는 방식, 한 번에 하나의 패킷만을 전송할 수 있음&lt;/p&gt;
&lt;h3 id="슬라이딩-윈도우-sliding-window"&gt;슬라이딩 윈도우 (Sliding Window)&lt;/h3&gt;
&lt;p&gt;ACK를 이용해서 송신 데이터의 양을 조절하는 방식, ACK를 받지 않더라도 미리 정해진 패킷의 수 만큼 연속적으로 전송하는 방식&lt;/p&gt;</description></item><item><title>Network. TCP vs. UDP</title><link>https://kelly-chui.github.io/posts/cs-network-tcp-vs-udp/</link><pubDate>Fri, 31 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-tcp-vs-udp/</guid><description>&lt;h2 id="tcp-vs-udp"&gt;TCP vs. UDP&lt;/h2&gt;
&lt;p&gt;TCP와 UDP는 모두 전송 계층에서 동작하는 프로토콜이지만, 연결 방식과 데이터 전송 방식이 다르다.&lt;/p&gt;
&lt;p&gt;TCP는 신뢰성을 우선으로 하고, UDP는 속도와 실시간성을 우선으로 설계되었다.&lt;/p&gt;
&lt;h2 id="비교"&gt;비교&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구분&lt;/th&gt;
&lt;th&gt;TCP&lt;/th&gt;
&lt;th&gt;UDP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;연결 방식&lt;/td&gt;
&lt;td&gt;연결 지향 (Connection-oriented)&lt;/td&gt;
&lt;td&gt;비연결형 (Connectionless)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;신뢰성&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;순서 보장&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 전송 방식&lt;/td&gt;
&lt;td&gt;스트림(Stream)&lt;/td&gt;
&lt;td&gt;데이터그램(Datagram)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;흐름 제어&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;혼잡 제어&lt;/td&gt;
&lt;td&gt;O&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;헤더 크기&lt;/td&gt;
&lt;td&gt;20~60 Byte&lt;/td&gt;
&lt;td&gt;8 Byte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;속도&lt;/td&gt;
&lt;td&gt;상대적으로 느림&lt;/td&gt;
&lt;td&gt;상대적으로 빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="언제-사용할까"&gt;언제 사용할까?&lt;/h2&gt;
&lt;h3 id="tcp"&gt;TCP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;웹 서비스 (HTTP, HTTPS)&lt;/li&gt;
&lt;li&gt;이메일 (SMTP)&lt;/li&gt;
&lt;li&gt;파일 전송 (FTP)&lt;/li&gt;
&lt;li&gt;데이터의 정확성이 중요한 서비스&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="udp"&gt;UDP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;DHCP&lt;/li&gt;
&lt;li&gt;실시간 스트리밍&lt;/li&gt;
&lt;li&gt;VoIP&lt;/li&gt;
&lt;li&gt;온라인 게임&lt;/li&gt;
&lt;li&gt;빠른 응답이 중요한 서비스&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="선택-기준"&gt;선택 기준&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;데이터의 정확성과 순서가 중요하다면 TCP를 사용한다.&lt;/li&gt;
&lt;li&gt;일부 패킷 손실이 발생하더라도 실시간성이 더 중요하다면 UDP를 사용한다.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Network. TCP(Transmission Control Protocol)</title><link>https://kelly-chui.github.io/posts/cs-network-tcp/</link><pubDate>Fri, 31 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-tcp/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;TCP(Transmission Control Protocol)는 전송 계층(L4)에서 동작하는 연결 지향(Connection-oriented) 프로토콜이다.&lt;/p&gt;
&lt;p&gt;신뢰성 있는 데이터 전송을 위해 연결 설정, 순서 제어, 오류 제어, 흐름 제어, 혼잡 제어 등의 기능을 제공한다.&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;신뢰성 있는 연결형 서비스 제공&lt;/li&gt;
&lt;li&gt;포트 번호를 이용한 다중화, 순서 제어, 오류 제어, 흐름 제어, 혼잡 제어 기능 제공&lt;/li&gt;
&lt;li&gt;애플리케이션에는 메시지 경계를 보존하지 않는 연속된 바이트 스트림을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="tcp-헤더"&gt;TCP 헤더&lt;/h3&gt;
&lt;p&gt;TCP 세그먼트 앞부분에 위치한 데이터 전송을 위한 제어 정보를 포함하는 구조, 20바이트로 구성되며 최대 60바이트로 확장 가능&lt;/p&gt;</description></item><item><title>Network. UDP(User Datagram Protocol)</title><link>https://kelly-chui.github.io/posts/cs-network-udp/</link><pubDate>Fri, 31 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-udp/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;UDP(User Datagram Protocol)는 전송 계층(L4)에서 동작하는 비연결형(Connectionless) 프로토콜이다.&lt;/p&gt;
&lt;p&gt;연결 설정 없이 데이터를 빠르게 전송하며, 신뢰성보다 실시간성이 중요한 환경에서 주로 사용된다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;UDP: User Datagram Protocol&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OSI 7계층에서 전송 계층(L4)에 해당&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;h3 id="장점"&gt;장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;데이터 전송 전에 연결을 설정하지 않는 비연결형 서비스
&lt;ul&gt;
&lt;li&gt;지연 시간이 낮음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단순한 프로토콜 구조
&lt;ul&gt;
&lt;li&gt;헤더 크기가 작고, 오버헤드가 적음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IP 계층의 유니캐스트, 브로드캐스트, 멀티캐스트 전송에 사용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="단점"&gt;단점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;신뢰성 부족
&lt;ul&gt;
&lt;li&gt;패킷 손실, 순서 오류, 중복이 발생해도 복구할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;애플리케이션 수준의 보완 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="데이터그램-패킷-통신"&gt;데이터그램 패킷 통신&lt;/h3&gt;
&lt;p&gt;각 데이터그램은 다른 데이터그램과 독립적으로 전달된다. UDP 자체에는 순서 번호, 재전송, 중복 제거 기능이 없으므로 도착 순서나 전달 성공을 보장하지 않는다.&lt;/p&gt;</description></item><item><title>Algorithm. Counter Clock Wise</title><link>https://kelly-chui.github.io/posts/cs-algorithm-counter-clock-wise/</link><pubDate>Thu, 30 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-algorithm-counter-clock-wise/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;2차원 평면 위에서 두 선분이 주어졌을 때 두 선분의 교차 여부를 판단하는 알고리즘&lt;/p&gt;
&lt;h2 id="아이디어"&gt;아이디어&lt;/h2&gt;
&lt;p&gt;2차원 평면 상에 3개의 점이 있을 때, 이들을 이루는 방향을 계산해서 두 선분의 교차 여부를 판단한다.&lt;/p&gt;
&lt;p&gt;여기서 말하는 3개의 점은 기준이 되는 선분의 양 끝점($P_1$, $P_2$라 하면)과, 나머지 선분의 한 끝점($Q_1$ 또는 $Q_2$)을 말한다.&lt;/p&gt;
&lt;p&gt;총 4개의 점인데 왜 3개의 점이냐고 하냐면, 기준이 되는 선분의 양 끝점과 나머지 선분의 한 끝점을 이용해 각각 CCW를 계산하기 때문이다.&lt;/p&gt;</description></item><item><title>Swift. Associated Type</title><link>https://kelly-chui.github.io/posts/swift-associated-type/</link><pubDate>Sun, 26 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swift-associated-type/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;Swift의 프로토콜은 구현이 아니라 요구사항만 정의한다. 그런데 어떤 프로토콜은 사용할 타입을 미리 알 수 없는 경우가 있다.&lt;/p&gt;
&lt;p&gt;예를 들어, 아래와 같은 &lt;code&gt;Container&lt;/code&gt; 프로토콜을 만든다고 생각해 보자.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;Container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;???)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;append&lt;/code&gt;가 받을 타입은 무엇이어야 할까?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Int&lt;/code&gt;일 수도 있고, &lt;code&gt;String&lt;/code&gt;일 수도 있으며, 사용자가 직접 만든 타입일 수도 있다. 하지만 프로토콜이 특정 타입에 종속되면 재사용성이 크게 떨어진다.&lt;/p&gt;
&lt;p&gt;이럴 때 사용하는 것이 Associated Type이다. 처음에는 Generic으로도 해결할 수 있을 것 같다는 생각이 들었는데, 프로토콜은 Generic을 사용할 수 없다.&lt;/p&gt;</description></item><item><title>SniffMEET. Diffable Data Source에서 이미지가 갱신되지 않은 이유</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-diffable-data-source-image-update/</link><pubDate>Mon, 20 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-diffable-data-source-image-update/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;SniffMeet의 메이트 리스트 화면은 &lt;code&gt;UITableViewDataSource&lt;/code&gt;를 직접 구현해서 셀을 구성하고 있었다. 이후 테이블 뷰와 컬렉션 뷰에서 Diffable DataSource를 사용해보기로 했고, 먼저 메이트 리스트 화면에 적용해보려고 했다.&lt;/p&gt;
&lt;p&gt;처음에는 어렵지 않을 거라고 생각했다. 섹션과 아이템 타입을 만들고, snapshot을 적용하면 기존 &lt;code&gt;reloadData()&lt;/code&gt;보다 깔끔하게 업데이트할 수 있을 것 같았다. 하지만 실제로는 이미지 갱신이 제대로 동작하지 않았다. 더 정확히는 프로필 이미지 데이터는 받아오는데, Diffable DataSource가 셀을 다시 구성할 때는 이미지가 계속 &lt;code&gt;nil&lt;/code&gt;로 남아 있었다.&lt;/p&gt;
&lt;p&gt;결국 이 작업은 성공적으로 마무리하지 못했다. 그래도 실패한 이유를 다시 정리해보니, 문제는 Diffable DataSource API 자체가 아니라 item의 identity와 표시 상태를 제대로 구분하지 못한 데 있었다.&lt;/p&gt;</description></item><item><title>OS. IPC(Inter-Process Communication)</title><link>https://kelly-chui.github.io/posts/cs-os-ipc/</link><pubDate>Sun, 19 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-os-ipc/</guid><description>&lt;p&gt;Date: January 19, 2025
Multi-select: Process&lt;/p&gt;
&lt;h2 id="ipc"&gt;IPC&lt;/h2&gt;
&lt;p&gt;여러 개의 독립적인 프로세스들이 서로 데이터를 주고받을 때 사용하는 메커니즘을 IPC(Inter Process Communication)라고 한다.&lt;/p&gt;
&lt;p&gt;각각의 프로세스는 별개의 메모리 공간을 가지기 때문에, 서로 직접 메모리에 접근할 수 없기 때문에 IPC는 프로세스 간에 데이터를 교환하는 방법을 제공한다.&lt;/p&gt;
&lt;h2 id="메세지-패싱"&gt;메세지 패싱&lt;/h2&gt;
&lt;p&gt;직접 메모리를 공유하지 않고 메세지를 통해 데이터를 주고받는 방식, 격리성을 보장할 수 있는 장점이 있지만 속도가 느리고 메모리 소비가 증가한다는 단점이 있음&lt;/p&gt;
&lt;h3 id="주요방식"&gt;주요방식&lt;/h3&gt;
&lt;h4 id="simple"&gt;Simple&lt;/h4&gt;
&lt;p&gt;간단히 메세지를 보내고 받는 방식&lt;/p&gt;</description></item><item><title>SniffMEET. 프로필 이미지 다운샘플링과 썸네일 분리하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-profile-image-downsampling-thumbnails/</link><pubDate>Fri, 17 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-profile-image-downsampling-thumbnails/</guid><description>&lt;h2 id="개요"&gt;개요&lt;/h2&gt;
&lt;p&gt;사용자가 고해상도 사진을 그대로 업로드하면, 앱에서는 훨씬 작은 크기로만 이미지를 표시하는데도 원본 이미지를 계속 전송하고 저장하게 된다.&lt;/p&gt;
&lt;p&gt;SniffMeet에서도 프로필 이미지는 홈 화면의 프로필 카드나 메이트 리스트의 작은 썸네일로 표시되는 경우가 대부분이었다. 그런데 원본 이미지를 그대로 업로드하고, 목록에서도 같은 이미지를 다시 내려받고 있었다.&lt;/p&gt;
&lt;p&gt;불필요한 네트워크 사용량과 메모리 사용을 줄이기 위해 두 가지를 적용했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;업로드 전에 프로필 이미지를 앱에서 필요한 크기로 다운샘플링한다.&lt;/li&gt;
&lt;li&gt;메이트 리스트에서는 원본 프로필 이미지가 아니라 별도의 썸네일 이미지를 내려받는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="다운샘플링-기준-정하기"&gt;다운샘플링 기준 정하기&lt;/h2&gt;
&lt;p&gt;이미지를 어느 크기까지 줄일지 먼저 정해야 했다. 기준은 앱에서 프로필 이미지가 가장 크게 표시되는 홈 화면의 프로필 카드로 잡았다.&lt;/p&gt;</description></item><item><title>SniffMEET. NI·MPC 프로필 드랍 흐름 소유권 고민하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-ni-mpc-profile-drop-ownership/</link><pubDate>Tue, 14 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-ni-mpc-profile-drop-ownership/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;SniffMeet의 프로필 드랍 기능은 주변 사용자를 찾고, 기기 간 연결을 만들고, 거리와 방향 조건을 만족했을 때 프로필을 전달하는 흐름이다.&lt;/p&gt;
&lt;p&gt;겉으로 보면 &amp;ldquo;주변 사람 찾기&amp;quot;와 &amp;ldquo;프로필 보내기&amp;quot;를 나누면 될 것 같았다. 하지만 실제 흐름을 펼쳐보니 MPC, NI, 유즈케이스, 인터랙터가 서로 맞물려 있었고, 단순히 기능 이름으로 유즈케이스를 나누기 어려웠다.&lt;/p&gt;
&lt;p&gt;이 글은 프로필 드랍 흐름을 유즈케이스로 나누면서 고민했던 지점을 정리한 기록이다.&lt;/p&gt;
&lt;h2 id="기존에-생각한-흐름"&gt;기존에 생각한 흐름&lt;/h2&gt;
&lt;p&gt;당시 프로필 드랍은 대략 다음 순서로 동작한다고 봤다.&lt;/p&gt;</description></item><item><title>SniffMEET. OSSignposter로 앱 내부 작업 구간 측정하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-os-signposter-intervals/</link><pubDate>Tue, 14 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-os-signposter-intervals/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;성능 개선을 하려면 먼저 어떤 작업이 얼마나 걸리는지 볼 수 있어야 한다. CPU 사용량만 보면 어느 시점에 부하가 생겼는지는 알 수 있지만, 앱 내부의 어떤 작업이 그 구간에 실행됐는지는 바로 드러나지 않는다.&lt;/p&gt;
&lt;p&gt;그래서 Instruments에서 앱 내부 작업 구간을 이름으로 확인할 수 있도록 &lt;code&gt;OSSignposter&lt;/code&gt;를 래핑해보기로 했다.&lt;/p&gt;
&lt;h2 id="어디에-붙일까"&gt;어디에 붙일까?&lt;/h2&gt;
&lt;p&gt;처음에는 측정용 타입을 따로 만들지, 기존 &lt;code&gt;SNMLogger&lt;/code&gt;에 붙일지 고민했다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;subsystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;SniffMeet&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;SNMLogger&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;별도의 &lt;code&gt;SNMBenchMarker&lt;/code&gt; 같은 타입을 만들 수도 있었지만, 이미 프로젝트에 로그 시스템이 있었기 때문에 기존 &lt;code&gt;SNMLogger&lt;/code&gt;에 통합하는 쪽을 선택했다.&lt;/p&gt;</description></item><item><title>Network. URI(Uniform Resource Identifier)</title><link>https://kelly-chui.github.io/posts/cs-network-uri-urn-url/</link><pubDate>Sun, 12 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-uri-urn-url/</guid><description>&lt;h2 id="uri-uniform-resource-identifier"&gt;URI (Uniform Resource Identifier)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;자원(파일, 웹 페이지, 이메일 주소)등을 식별하는 문자열&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;URI는 URL과 URN을 포함하는 상위 개념이다.&lt;/p&gt;
&lt;h2 id="url-uniform-resource-locator"&gt;URL (Uniform Resource Locator)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;자원의 위치(Location)와 접근 방법을 나타내는 URI&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;HTTP, HTTPS, FTP 등의 프로토콜을 포함할 수 있다.&lt;/li&gt;
&lt;li&gt;프로토콜, 호스트, 경로, 쿼리 등을 통해 자원에 접근하는 방법을 나타낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="urn-uniform-resource-name"&gt;URN (Uniform Resource Name)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;자원의 이름(Name)으로 식별하는 URI&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;자원의 위치와 관계없이 고유한 이름으로 식별한다.&lt;/li&gt;
&lt;li&gt;대표적으로 ISBN, ISSN 등이 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="관계"&gt;관계&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;URI
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── URL
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── URN&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>OS. Context Switching</title><link>https://kelly-chui.github.io/posts/cs-os-context-switching/</link><pubDate>Sun, 12 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-os-context-switching/</guid><description>&lt;h2 id="컨텍스트-스위칭"&gt;컨텍스트 스위칭&lt;/h2&gt;
&lt;p&gt;CPU가 현재 실행 중인 프로세스나 스레드를 중단하고, 다른 프로세스나 스레드를 실행하는 과정. 멀티 태스킹 환경에서 하나의 CPU가 여러 작업을 번갈아 가며 처리할 수 있게 만들어 준다.&lt;/p&gt;
&lt;h3 id="언제-발생하나"&gt;언제 발생하나?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CPU 스케줄러가 다른 작업을 선택했을 때(그러면 다른 프로세스를 써야하니까)&lt;/li&gt;
&lt;li&gt;실행 중인 작업이 블로킹 되었을때 (I/ O같은게 들어왔다거나 할 때)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="과정"&gt;과정&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;현재 작업(프로세스, 스레드)의 컨텍스트를 저장한다.&lt;/li&gt;
&lt;li&gt;다음에 실행할 작업의 컨텍스트를 복원한다.&lt;/li&gt;
&lt;li&gt;CPU가 새로운 작업을 실행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코스트"&gt;코스트&lt;/h3&gt;
&lt;p&gt;컨텍스트 스위칭을 할 때, 상태를 저장하고 로드하는 과정에서 메모리 접근, 레지스터 저장, 복원과 같은 작업 때문에 시간과 자원을 사용하게 된다.&lt;/p&gt;</description></item><item><title>OS. Deadlock</title><link>https://kelly-chui.github.io/posts/cs-os-deadlock/</link><pubDate>Sun, 12 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-os-deadlock/</guid><description>&lt;h2 id="데드락"&gt;데드락&lt;/h2&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/cs-os-deadlock/image-001.svg"&gt;&lt;p&gt;두 개 이상의 프로세스나 스레드가 서로 상대방이 점유하고 있는 자원을 기다리며, 서로 무한히 기다리는 상태에 빠지는 현상&lt;/p&gt;
&lt;h2 id="데드락의-발생-조건"&gt;데드락의 발생 조건&lt;/h2&gt;
&lt;p&gt;다음 네 가지 Coffman 조건이 동시에 성립할 때 데드락이 발생할 수 있다. 각 조건은 데드락의 필요 조건이지만, 네 조건이 성립한다고 해서 모든 실행에서 반드시 데드락이 발생하는 것은 아니다.&lt;/p&gt;
&lt;h3 id="상호-배제mutual-exclusion"&gt;상호 배제(Mutual Exclusion)&lt;/h3&gt;
&lt;p&gt;한 번에 하나의 작업만 사용할 수 있는 자원이 존재하는 상태다.&lt;/p&gt;
&lt;h3 id="점유-대기hold-and-wait"&gt;점유 대기(Hold and Wait)&lt;/h3&gt;
&lt;p&gt;작업이 하나 이상의 자원을 이미 보유한 상태에서 다른 작업이 가진 추가 자원을 기다리는 상태다.&lt;/p&gt;</description></item><item><title>프로세스와 스레드</title><link>https://kelly-chui.github.io/posts/cs-os-process-thread/</link><pubDate>Sun, 12 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-os-process-thread/</guid><description>&lt;h2 id="프로세스"&gt;프로세스&lt;/h2&gt;
&lt;p&gt;컴퓨터에서 실행 중인 프로그램의 인스턴스, 프로그램이 메모리에 올라가면 프로세스가 된다.&lt;/p&gt;
&lt;h3 id="프로세스의-상태"&gt;프로세스의 상태&lt;/h3&gt;
&lt;p&gt;운영체제마다 세부 상태는 다르지만, 기본적인 5상태 모델은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;생성(New): 프로세스가 만들어지는 중인 상태&lt;/li&gt;
&lt;li&gt;준비(Ready): 실행에 필요한 자원을 갖추고 CPU 할당을 기다리는 상태&lt;/li&gt;
&lt;li&gt;실행(Running): CPU에서 명령을 실행하고 있는 상태&lt;/li&gt;
&lt;li&gt;대기(Waiting, Blocked): I/O 완료나 이벤트 발생을 기다리는 상태&lt;/li&gt;
&lt;li&gt;종료(Terminated): 실행이 끝난 상태&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CPU 스케줄러가 준비 상태의 프로세스를 선택하면 실행 상태로 이동한다. 할당 시간이 끝나거나 선점되면 다시 준비 상태가 되고, I/O를 요청하면 대기 상태로 이동한다. 기다리던 작업이 완료되면 다시 준비 상태로 돌아간다.&lt;/p&gt;</description></item><item><title>Data Structure. Hash Table</title><link>https://kelly-chui.github.io/posts/cs-data-structure-hash-table/</link><pubDate>Sat, 11 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-data-structure-hash-table/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;키, 값 쌍으로 데이터를 저장하는 자료구조. 데이터 삽입, 검색, 삭제가 빠르다. (스위프트에서 사용하는 딕셔너리도 해시 테이블이다.)&lt;/p&gt;
&lt;p&gt;해시 테이블은 키를 배열의 인덱스로 직접 사용하는 대신, 해시 함수를 통해 키를 일정한 범위의 해시 값으로 변환한다. 이 덕분에 배열 전체를 순회하지 않고도 데이터가 저장된 위치에 빠르게 접근할 수 있다.&lt;/p&gt;
&lt;h2 id="구조"&gt;구조&lt;/h2&gt;
&lt;p&gt;해시 테이블은 배열과 해시 함수로 구성된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;배열: 데이터를 저장할 배열, 배열의 인덱스는 해시 값을 뜻함&lt;/li&gt;
&lt;li&gt;해시 함수: 키를 해시 값으로 변환하는 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;키를 해시 함수에 넣어서 계산된 해시 값을 기반으로, 배열의 인덱스에 값을 저장한다.&lt;/p&gt;</description></item><item><title>SniffMEET. DTO와 Entity의 경계 점검하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-dto-entity-boundaries/</link><pubDate>Sat, 11 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-dto-entity-boundaries/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;SniffMeet에 기능이 붙으면서 DTO와 Entity가 빠르게 늘어났다. 처음에는 필요한 타입을 그때그때 만들면 됐지만, 어느 순간부터 어떤 타입이 어느 레이어에서 쓰이는지 헷갈리기 시작했다.&lt;/p&gt;
&lt;p&gt;특히 &lt;code&gt;UserInfoDTO&lt;/code&gt;, &lt;code&gt;UserInfo&lt;/code&gt;, &lt;code&gt;DogInfo&lt;/code&gt;, &lt;code&gt;Mate&lt;/code&gt;처럼 비슷한 정보를 담는 타입들이 여러 곳에서 서로 다른 이름으로 사용되고 있었다. 그래서 바로 코드를 고치기보다, 먼저 현재 타입들이 어디에서 쓰이고 있는지 정리해보기로 했다.&lt;/p&gt;
&lt;h2 id="먼저-한-일-사용처-조사"&gt;먼저 한 일: 사용처 조사&lt;/h2&gt;
&lt;p&gt;가장 먼저 DTO, Entity, Supabase 관련 Request/Response 타입을 나눠서 사용처를 훑어봤다.&lt;/p&gt;
&lt;p&gt;전체 목록을 보면 타입 수가 많은 것도 문제였지만, 더 큰 문제는 몇몇 타입의 사용처가 너무 넓다는 점이었다.&lt;/p&gt;</description></item><item><title>SniffMEET. 비동기 태스크와 액터 점검하기 (1)</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-task-mainactor-boundaries-part-1/</link><pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-task-mainactor-boundaries-part-1/</guid><description>&lt;h2 id="작업-내역"&gt;작업 내역&lt;/h2&gt;
&lt;p&gt;이번 작업에서는 &lt;code&gt;Task&lt;/code&gt;, &lt;code&gt;async/await&lt;/code&gt;, &lt;code&gt;@MainActor&lt;/code&gt;가 섞여 있던 부분을 화면별로 점검했다.&lt;/p&gt;
&lt;p&gt;앱 시작 흐름부터 프로필 등록, 메이트 목록, 산책 응답까지 비동기 경계를 다시 살펴보고, 각 화면에서 책임이 어디에 있어야 하는지 정리했다.&lt;/p&gt;
&lt;h3 id="앱-시작-플로우"&gt;앱 시작 플로우&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;UIWindow&lt;/code&gt;의 루트 뷰 컨트롤러를 결정하는 흐름은 &lt;code&gt;@MainActor&lt;/code&gt;로 두고, 그 안에서 세션 복원이 끝나기를 기다렸다. &lt;code&gt;await&lt;/code&gt;로 대기하는 동안에는 메인 액터를 점유하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;displayInitialScreen&lt;/code&gt;이 &lt;code&gt;MainActor&lt;/code&gt; 안에서 실행되는지 breakpoint로 확인했고, &lt;code&gt;displayOnBoardingView&lt;/code&gt;는 그대로 &lt;code&gt;MainActor&lt;/code&gt;에 남겨 두었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// AppRouter.swift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;displayInitialScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;MainActor&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SupabaseAuthManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restoreSession&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;displayTabBar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;displayOnBoardingView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="프로필-입력-및-등록"&gt;프로필 입력 및 등록&lt;/h3&gt;
&lt;p&gt;프로필 입력 부분은 전달만 하는 역할이라 비동기 처리가 필요하지 않았다.&lt;/p&gt;</description></item><item><title>SniffMEET. 비동기 태스크와 액터 점검하기 (2)</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-task-mainactor-boundaries-part-2/</link><pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-task-mainactor-boundaries-part-2/</guid><description>&lt;h3 id="메이트-요청"&gt;메이트 요청&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;didTabAcceptButton&lt;/code&gt;과 &lt;code&gt;saveMateInfo&lt;/code&gt;를 따라가 보니 유스케이스 실행을 위해 &lt;code&gt;Task&lt;/code&gt;가 존재했고, Combine의 &lt;code&gt;sink&lt;/code&gt; 클로저 안에서도 &lt;code&gt;Task&lt;/code&gt;를 생성하고 있었다. Interactor에서 태스크를 묶으면 저장 완료를 알리는 메서드가 따로 필요해 보였다.&lt;/p&gt;
&lt;p&gt;Presenter 메서드는 &lt;code&gt;async&lt;/code&gt;로 바꾸고, &lt;code&gt;View&lt;/code&gt;의 &lt;code&gt;sink&lt;/code&gt;에서는 &lt;code&gt;Task&lt;/code&gt;를 통해 호출하도록 두었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;acceptButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;touchUpInside&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;weak&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;didTapAcceptButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="n"&gt;DogProfileDTO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;closeTheView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// RequestMatePresenter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;closeTheView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;router&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;dismissView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didTapAcceptButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SNMLogger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;id: &lt;/span&gt;&lt;span class="si"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;await&lt;/span&gt; &lt;span class="n"&gt;interactor&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;saveMateInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="산책-요청-및-응답"&gt;산책 요청 및 응답&lt;/h3&gt;
&lt;h4 id="respondwalkpresenter"&gt;&lt;code&gt;RespondWalkPresenter&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;산책 요청은 &lt;code&gt;Task&lt;/code&gt;로 Interactor에 존재했고, 위치 변환은 Presenter에서 &lt;code&gt;await&lt;/code&gt;로 처리했다.&lt;/p&gt;</description></item><item><title>Programmers. 순위 검색</title><link>https://kelly-chui.github.io/ps/2025/ps-programmers-ranking-search/</link><pubDate>Tue, 07 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2025/ps-programmers-ranking-search/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/72412"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/72412&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;많이 해맨 문제다. 처음에는 다음과 같이 알고리즘을 생각했다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;일단 쿼리의 개수와 &lt;code&gt;info&lt;/code&gt; 배열의 크기를 생각해보면 &lt;code&gt;filter&lt;/code&gt;를 사용하는 문제는 아님&lt;/li&gt;
&lt;li&gt;바이너리 서치, Upper bound와 Lower bound의 차이가 해당하는 원소의 개수가 같음&lt;/li&gt;
&lt;li&gt;&lt;code&gt;info&lt;/code&gt; 배열을 잘 정렬해서 바이너리 서치만 하면 쉽게 해결될 문제&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;하지만 조금만 생각해보면 이러한 방식의 알고리즘은 문제를 절대로 해결할 수 없다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;우선 쿼리의 조건들이 독립적이다. 정렬 기준에 따라서 포함되어야 할 값이 포함되지 않게 된다.&lt;/li&gt;
&lt;li&gt;그렇다고 바이너리 서치 -&amp;gt; 다시 정렬을 반복하기엔 차라리 &lt;code&gt;filter&lt;/code&gt;를 쓰는게 더 시간 복잡도가 더 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;다음에 생각한 방식은 트리를 이용하는 방식이었다.&lt;/p&gt;</description></item><item><title>SniffMEET. Instruments로 성능 개선 후보 찾기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-instruments-performance-candidates/</link><pubDate>Tue, 07 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-instruments-performance-candidates/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;성능 개선이 필요해 보이는 지점을 감으로 고르지 않기 위해, 먼저 SniffMeet의 주요 흐름에서 CPU와 네트워크 사용량을 훑어봤다.&lt;/p&gt;
&lt;p&gt;이 측정만으로 병목 원인을 확정할 수는 없다. 다만 어떤 화면과 기능을 먼저 의심해야 하는지, 이후 리팩토링 후보를 정하는 기준으로는 충분했다.&lt;/p&gt;
&lt;h2 id="cpu-사용량-측정"&gt;CPU 사용량 측정&lt;/h2&gt;
&lt;p&gt;Instruments의 Time Profiler로 주요 사용자 흐름을 따라가며 CPU 사용량이 튀는 구간을 확인했다.&lt;/p&gt;
&lt;img alt="Time Profiler에서 CPU 사용량이 튀는 구간" loading="lazy" src="https://kelly-chui.github.io/posts/sniffmeet-dev-log-instruments-performance-candidates/image-001-optimized-image.webp"&gt;&lt;p&gt;측정 중 비교적 사용량이 높았던 지점은 다음과 같았다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;시점&lt;/th&gt;
&lt;th&gt;동작&lt;/th&gt;
&lt;th&gt;관찰&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0:26&lt;/td&gt;
&lt;td&gt;프로필 입력 뷰 로드&lt;/td&gt;
&lt;td&gt;CPU 70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0:53&lt;/td&gt;
&lt;td&gt;텍스트 필드 입력&lt;/td&gt;
&lt;td&gt;CPU 70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1:44&lt;/td&gt;
&lt;td&gt;사진, 닉네임 입력 뷰 로드&lt;/td&gt;
&lt;td&gt;CPU 70%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2:08&lt;/td&gt;
&lt;td&gt;포토피커&lt;/td&gt;
&lt;td&gt;CPU 90%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3:00&lt;/td&gt;
&lt;td&gt;등록 완료 버튼 터치&lt;/td&gt;
&lt;td&gt;CPU 100%, 약 0.7초 유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3:28&lt;/td&gt;
&lt;td&gt;메이트 리스트 뷰 로드&lt;/td&gt;
&lt;td&gt;CPU 50%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3:41&lt;/td&gt;
&lt;td&gt;산책 요청 보내기 터치&lt;/td&gt;
&lt;td&gt;CPU 80%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4:10&lt;/td&gt;
&lt;td&gt;지도 로드&lt;/td&gt;
&lt;td&gt;CPU 95%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5:05&lt;/td&gt;
&lt;td&gt;요청 보내기&lt;/td&gt;
&lt;td&gt;CPU 100%, 약 0.2초&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6:36&lt;/td&gt;
&lt;td&gt;MPC 연결&lt;/td&gt;
&lt;td&gt;CPU 100%, 약 1.2초&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;특히 회원가입 완료 버튼을 눌렀을 때와 MPC 연결 시점이 눈에 띄었다. 회원가입 완료 시점에는 메인 스레드에서만 작업이 몰리는 것처럼 보였고, MPC 연결 시점에는 MultipeerConnectivity 관련 스레드가 지속적으로 동작했다.&lt;/p&gt;</description></item><item><title>Algorithm. LCS(Subsequence)</title><link>https://kelly-chui.github.io/posts/cs-algorithm-lcs-subsequence/</link><pubDate>Thu, 02 Jan 2025 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-algorithm-lcs-subsequence/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;두 문자열이 있을 때, 가장 긴 공통 부분 문자열을 찾아내는 알고리즘, 부분 문자열이란 원소들이 원래 순서를 유지하면서 일부 원소를 생략할 수 있는 형태를 말함&lt;/p&gt;
&lt;p&gt;예시:&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;문자열 A: A**B**CB**DAB**
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;문자열 B: **BD**C**AB**B&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;A와 B의 LCS는 BDAB라고 할 수 있다.&lt;/p&gt;
&lt;h2 id="아이디어"&gt;아이디어&lt;/h2&gt;
&lt;p&gt;2차원 배열을 통해 중간 결과를 메모이제이션 한다. 이 배열은 두 문자열의 길이에 따라 결정된다.&lt;/p&gt;
&lt;h2 id="알고리즘"&gt;알고리즘&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;편의상 첫 번째 열과 행은 0으로 초기화 한다. 빈 문자열과 비교했을 때의 경우를 처리할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;-&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ol&gt;
&lt;li&gt;두 번째 문자열의 문자를 차례대로 가져와 비교한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;-&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;테이블의 각 원소는 그 시점의 substring간의 LCS를 의미한다. 즉 위 표에서 1인 원소는 substring “AB”와 “B”의 LCS의 길이가 1임을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;앞선 결과를 기반으로 LCS의 크기를 계산한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;-&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;B와 C는 같지 않더라도, “ABC”와 “B”를 비교하는 것과 같으므로, 이전에 “AB”와 “B”를 비교한 값인 1이 유지된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;만약 두 문자가 다른 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;-&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;B와 D는 다르지만, “AB”와 “BD”의 LCS의 길이는 1이다. 3번의 경우와 합쳐서 두 원소가 다르지 않을 때, DP 테이블을 채우는 점화식을 세울 수 있다.&lt;/li&gt;
&lt;li&gt;dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;두 문자가 같은 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;-&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;D&lt;/th&gt;
&lt;th&gt;A&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;두 문자가 같은 경우, 즉 위 표의 상황에서는 “ABCBD”와 “BD”의 LCS의 크기를 구하는 경우가 된다. 이 경우는 “ABCB”와 “B”의 LCS의 크기에서 원소 “D”가 더해진 것과 같으므로, 대각선 위에 있는 값에서 1을 더한 값이 된다.&lt;/li&gt;
&lt;li&gt;dp[i][j] = dp[i - 1][j - 1] + 1&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="동작-원리"&gt;동작 원리&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;DP 테이블을 채우면서 두 문자가 다른 경우
&lt;ul&gt;
&lt;li&gt;이전에 계산한 결과를 그대로 유지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;두 문자가 같은 경우
&lt;ul&gt;
&lt;li&gt;그 문자가 없는 경우의 LCS의 크기에서 1을 더한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;점화식&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;B&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="기타"&gt;기타&lt;/h2&gt;
&lt;h3 id="길이와-실제-문자열"&gt;길이와 실제 문자열&lt;/h3&gt;
&lt;p&gt;DP 테이블의 마지막 값인 &lt;code&gt;dp[m][n]&lt;/code&gt;은 LCS의 &lt;strong&gt;길이&lt;/strong&gt;만 나타낸다.&lt;/p&gt;</description></item><item><title>Algorithm. Binary Search off-by-one 에러 없이 구현하기</title><link>https://kelly-chui.github.io/posts/cs-algorithm-binary-search/</link><pubDate>Tue, 31 Dec 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-algorithm-binary-search/</guid><description>&lt;h2 id="off-by-one-error"&gt;off by one error&lt;/h2&gt;
&lt;p&gt;바이너리 서치를 할 때, 경계나 중간 값을 처리하면서 인덱스가 하나 어긋나는 에러&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;주요 원인은 바이너리 서치에 대한 이해 부족&lt;/li&gt;
&lt;li&gt;인덱스 레인지, high / low 갱신 방식, 중간값 계산 방식, 값 리턴 방식을 다양하게 생각해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="binary-search-테크닉"&gt;Binary Search 테크닉&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;else&lt;/code&gt;보다는 &lt;code&gt;else if&lt;/code&gt;를 사용하여 조건을 명확하게 표현하기&lt;/li&gt;
&lt;li&gt;오버플로우 방지를 위해서는 &lt;code&gt;mid&lt;/code&gt;를 계산할 때, &lt;code&gt;(low + high) / 2&lt;/code&gt;보다 &lt;code&gt;low + (high - low) / 2&lt;/code&gt;를 사용하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;바이너리 서치는 단순히 정렬된 배열에서 값을 찾는 알고리즘이 아니다. 바이너리 서치를 이용하여, 정확한 값을 찾는 경우보다 조건을 만족하는 첫 번째 또는 마지막 위치를 찾는 경우가 더 많다.&lt;/p&gt;</description></item><item><title>SniffMEET. anon-key와 익명 사용자의 접근 권한 구분</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-anon-access-control/</link><pubDate>Thu, 28 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-anon-access-control/</guid><description>&lt;h2 id="anon-role과-anon-user의-접근-권한-차이"&gt;anon-role과 anon-user의 접근 권한 차이&lt;/h2&gt;
&lt;p&gt;Public Scheme에 있는 테이블을 &lt;code&gt;anon-key&lt;/code&gt;로는 접근할 수 있었지만, &lt;code&gt;anon-user&lt;/code&gt;의 JWT 토큰으로는 접근하지 못하는 문제가 있었다.&lt;br&gt;
처음에는 둘이 비슷한 범주라고 생각했지만, 실제로는 권한 체계와 접근 방식이 달라서 같은 문제로 볼 수 없었다.&lt;/p&gt;
&lt;h3 id="문제를-확인하기-전-생각한-내용"&gt;문제를 확인하기 전 생각한 내용&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;anon-key&lt;/code&gt;, &lt;code&gt;anon-role&lt;/code&gt;, &lt;code&gt;anon-user&lt;/code&gt;의 차이부터 다시 정리했다.&lt;br&gt;
&lt;code&gt;anon-key&lt;/code&gt;를 이용한 접근은 &lt;code&gt;anon-role&lt;/code&gt;로 보고, &lt;code&gt;anon-user&lt;/code&gt;는 이메일 주소나 전화번호를 등록하지 않은 유저를 의미한다. 이 경우 role 자체는 &lt;code&gt;authenticated-role&lt;/code&gt;이었다.&lt;/p&gt;
&lt;p&gt;익명 유저가 접근했을 때 &lt;code&gt;200 OK&lt;/code&gt;가 뜨지만 실제 값을 가져오지 못하는 경우도 있었다.&lt;br&gt;
그래서 접근 자체는 허용되지만 &lt;code&gt;RLS&lt;/code&gt;에서 막히고 있다고 추정할 수 있었다.&lt;/p&gt;</description></item><item><title>SniffMEET. Storage 버킷과 접근 제어</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-storage-access-control/</link><pubDate>Sun, 24 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-storage-access-control/</guid><description>&lt;p&gt;SniffMEET의 프로필 이미지는 사용자 정보와 성격이 다르다. 사용자 이름이나 소개처럼 구조화된 데이터는 Database에 저장하고, 이미지 파일은 Storage에 저장하는 편이 적합하다.&lt;/p&gt;
&lt;p&gt;Storage의 Postgres 테이블에는 파일 자체가 아니라 버킷과 객체의 메타데이터가 기록된다.&lt;/p&gt;
&lt;h2 id="버킷과-객체-경로"&gt;버킷과 객체 경로&lt;/h2&gt;
&lt;p&gt;버킷은 파일을 묶는 최상위 컨테이너다. 사용자마다 버킷을 만드는 것보다 용도별 버킷을 만들고 객체 경로로 사용자를 구분하는 편이 관리하기 쉽다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;profile-images/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── {user-id}/profile.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── {user-id}/thumbnail.jpg&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 구조에서는 &lt;code&gt;profile-images&lt;/code&gt; 버킷이 공통된 공개 범위와 파일 제한을 담당하고, 사용자 ID가 포함된 경로를 RLS 정책에서 검사할 수 있다.&lt;/p&gt;</description></item><item><title>SniffMEET. Supabase 세션 갱신 요청이 실패한 이유</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-refresh-token-request/</link><pubDate>Thu, 21 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-refresh-token-request/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;Supabase 세션 갱신 요청이 제대로 동작하지 않았다. 세션 로직이나 네트워크 레이어 문제처럼 보였지만, 실제 원인은 요청 형식이었다. 당시 메모는 이랬다.&lt;/p&gt;
&lt;h2 id="수정"&gt;수정&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;&amp;#34;grant_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;refreshToken&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;grant_type&lt;/code&gt; 값을 Swift식 camelCase로 보내고 있었다. Supabase가 기대하는 값은 &lt;code&gt;refresh_token&lt;/code&gt;이었다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;&amp;#34;grant_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;refresh_token&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;body도 마찬가지였다. Supabase가 기대하는 key는 &lt;code&gt;refreshToken&lt;/code&gt;이 아니라 &lt;code&gt;refresh_token&lt;/code&gt;이었다. refresh 요청에서는 기존 access token의 &lt;code&gt;Authorization&lt;/code&gt; 헤더도 제거했다. (토큰을 갱신받기 위한 요청인데, 만료된 토큰을 보내는거니까 아무 의미 없다!)&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;{ &lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="s"&gt;refresh_token&lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;refreshToken&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\&amp;#34;&lt;/span&gt;&lt;span class="s"&gt; }&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;refresh 요청은 기존 access token으로 리소스에 접근하는 요청이 아니라, refresh token으로 새 세션을 발급받는 요청이기 때문이다.&lt;/p&gt;</description></item><item><title>SniffMEET. JWT와 Supabase RLS 정책에 연결하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-jwt-rls/</link><pubDate>Wed, 20 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-jwt-rls/</guid><description>&lt;p&gt;Supabase Auth로 로그인하면 클라이언트는 Access Token으로 JWT를 받는다. Supabase는 요청에 포함된 JWT를 검증하고, 그 안의 사용자 정보와 역할을 RLS 정책에 전달한다.&lt;/p&gt;
&lt;pre class="mermaid" data-mermaid-source="flowchart&amp;#43;LR%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;Client%5B%22%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%22%5D&amp;#43;--%3E%7C%22JWT%EB%A5%BC&amp;#43;%ED%8F%AC%ED%95%A8%ED%95%9C&amp;#43;%EC%9A%94%EC%B2%AD%22%7C&amp;#43;Supabase%5B%22Supabase&amp;#43;API%22%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;Supabase&amp;#43;--%3E%7C%22JWT&amp;#43;%EA%B2%80%EC%A6%9D%22%7C&amp;#43;Claims%5B%22sub%2C&amp;#43;role&amp;#43;%EB%93%B1%EC%9D%98&amp;#43;%ED%81%B4%EB%A0%88%EC%9E%84%22%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;Claims&amp;#43;--%3E&amp;#43;RLS%5B%22PostgreSQL&amp;#43;RLS&amp;#43;%EC%A0%95%EC%B1%85%22%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;RLS&amp;#43;--%3E&amp;#43;Database%5B%22%ED%97%88%EC%9A%A9%EB%90%9C&amp;#43;%ED%96%89%EB%A7%8C&amp;#43;%EC%A1%B0%ED%9A%8C&amp;#43;%EB%98%90%EB%8A%94&amp;#43;%EB%B3%80%EA%B2%BD%22%5D"&gt;&lt;/pre&gt;&lt;h2 id="jwt의-클레임"&gt;JWT의 클레임&lt;/h2&gt;
&lt;p&gt;JWT는 헤더, 페이로드, 서명으로 구성된다. 각 부분은 Base64URL로 인코딩되지만 암호화되지는 않으므로 페이로드에 비밀 정보를 넣으면 안 된다. 서명은 헤더와 페이로드가 변조되지 않았는지 검증하는 데 사용한다.&lt;/p&gt;
&lt;p&gt;Supabase의 JWT에는 다음과 같은 클레임이 포함된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sub&lt;/code&gt;: 사용자의 고유 ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;role&lt;/code&gt;: RLS를 적용할 PostgreSQL 역할&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iat&lt;/code&gt;: 토큰이 발급된 시각&lt;/li&gt;
&lt;li&gt;&lt;code&gt;exp&lt;/code&gt;: 토큰이 만료되는 시각&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="supabase에서-jwt-사용하기"&gt;Supabase에서 JWT 사용하기&lt;/h2&gt;
&lt;p&gt;RLS는 PostgreSQL이 행 단위로 접근을 제한하는 기능이다. Supabase에서는 &lt;code&gt;auth.uid()&lt;/code&gt;로 현재 JWT의 &lt;code&gt;sub&lt;/code&gt; 값을 가져와 행의 사용자 ID와 비교할 수 있다.&lt;/p&gt;</description></item><item><title>SniffMEET. RLS와 테이블 권한</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-rls-empty-response/</link><pubDate>Wed, 20 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-rls-empty-response/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;Supabase에서 anon key로 Public 테이블에 접근하면 데이터가 보이는데, 익명 로그인 후 받은 JWT access token으로 접근하면 &lt;code&gt;200 OK&lt;/code&gt;만 오고 데이터가 비어 있었다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-rls-empty-response/image-003-optimized-image.webp"&gt;&lt;p&gt;처음에는 authenticated role이 anon role보다 상위 권한이라고 생각해서 더 헷갈렸다. 하지만 Supabase에서는 role의 상하관계보다 RLS 정책을 어떻게 작성했는지가 더 중요했다.&lt;/p&gt;
&lt;h2 id="확인"&gt;확인&lt;/h2&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-rls-empty-response/image-002-optimized-image.webp"&gt;&lt;p&gt;JWT가 만료된 경우에는 &lt;code&gt;401 Unauthorized&lt;/code&gt;가 발생했다. 반면 RLS 조건에 맞지 않는 경우에는 요청 자체는 성공해서 &lt;code&gt;200 OK&lt;/code&gt;가 오지만, row가 필터링되어 데이터가 내려오지 않았다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-rls-empty-response/image-004-optimized-image.webp"&gt;&lt;p&gt;authenticated 유저가 읽을 수 있도록 다음 policy를 추가하자 데이터를 읽을 수 있었다.&lt;/p&gt;</description></item><item><title>Swift. Xcode 디버깅과 LLDB 기본 명령어</title><link>https://kelly-chui.github.io/posts/swift-xcode-lldb-debugging/</link><pubDate>Wed, 20 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swift-xcode-lldb-debugging/</guid><description>&lt;h2 id="lldb가-뭔가요"&gt;LLDB가 뭔가요&lt;/h2&gt;
&lt;p&gt;LLVM + Debugger&lt;/p&gt;
&lt;p&gt;LLVM 위에서 동작하는 디버거&lt;/p&gt;
&lt;h3 id="llvmlow-level-virtual-machine"&gt;LLVM(Low Level Virtual Machine)&lt;/h3&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/swift-xcode-lldb-debugging/image-001-optimized-image.webp"&gt;&lt;p&gt;프로그래밍 언어를 CPU 아키텍처가 이해할 수 있도록 컴파일 하는 과정을 생각해보면 (프로그래밍 언어의 종류 * CPU 아키텍처의 종류) 만큼의 경우의 수가 생긴다.&lt;/p&gt;
&lt;p&gt;LLVM은 LLVM-IR이라는 중간 언어를 만들어서 프로그래밍 언어를 LLVM-IR로 변역하고 이 LLVM-IR을 CPU 아키텍처에 맞는 기계어로 번역하게 해주는 역할을 함 어려운건 여기까지!&lt;/p&gt;
&lt;h2 id="xcode-debugging"&gt;XCode Debugging&lt;/h2&gt;
&lt;h3 id="breakpoint"&gt;BreakPoint&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;브레이크 포인트가 걸린 라인 직전 까지 실행 됨&lt;/li&gt;
&lt;li&gt;활성화/비활성화 할 수 있음&lt;/li&gt;
&lt;li&gt;다양한 옵션 지정 가능 (이름, LLDB 커맨드, 로그 작성 등등)…&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="debugging-bar"&gt;Debugging Bar&lt;/h3&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/swift-xcode-lldb-debugging/image-002-optimized-image.webp"&gt;&lt;ul&gt;
&lt;li&gt;Disable/enable breakpoints: 브레이크 포인트들을 활성화/비활성화&lt;/li&gt;
&lt;li&gt;Pause/continue execution: 다음 브레이크 포인트가 나올 때 까지 진행&lt;/li&gt;
&lt;li&gt;Step over: 다음 라인으로 넘어가기&lt;/li&gt;
&lt;li&gt;Step into: 현재 브레이크 포인트가 걸려있는 메소드로 들어가기&lt;/li&gt;
&lt;li&gt;Step out: 현재 메소드에서 벗어나기&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="lldb-직접-사용해보기"&gt;LLDB 직접 사용해보기&lt;/h2&gt;
&lt;h3 id="print-p"&gt;Print: &lt;code&gt;p&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;현재 메모리 상태에 있는 것을 출력한다.&lt;/p&gt;</description></item><item><title>SniffMEET. 익명 로그인 세션의 생성·복원·갱신 흐름</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-anonymous-session-lifecycle/</link><pubDate>Thu, 14 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-supabase-anonymous-session-lifecycle/</guid><description>&lt;h2 id="익명-로그인-생성-복원-갱신-로직-구현"&gt;익명 로그인 생성, 복원, 갱신 로직 구현&lt;/h2&gt;
&lt;p&gt;JWT, Refresh Token, 세션의 개념이 아직 명확하게 정리되지 않은 상태에서 익명 계정을 먼저 만들게 됐다. 개념이 명확하지 않아서, 세션 관리에 꽤 애를 먹었는데, 앱 재실행 이후에도 익명 계정을 어떻게 이어서 사용할지부터 정리할 필요가 있었다.&lt;/p&gt;
&lt;p&gt;생성, 복원, 갱신 로직은 서로 밀접하게 연결되어 있어서, 처음 앱을 실행했을 때와 다시 실행했을 때의 흐름을 먼저 구분해야 했다.&lt;/p&gt;
&lt;h3 id="실제-문제-해결-과정"&gt;실제 문제 해결 과정&lt;/h3&gt;
&lt;p&gt;먼저 시점별로 세션 상태를 표로 정리했다.&lt;/p&gt;</description></item><item><title>SniffMEET. 여러 VIPER 구현에서 Router 구조 비교하기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-viper-router-comparison/</link><pubDate>Tue, 12 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-viper-router-comparison/</guid><description>&lt;p&gt;VIPER에서 Router가 화면 전환을 담당한다는 원칙은 분명하다. 하지만 현재 화면을 어떻게 참조하는지, 다음 모듈은 누가 만드는지, AppRouter가 반드시 필요한지는 구현마다 달랐다.&lt;/p&gt;
&lt;p&gt;SniffMEET의 화면 구조를 정하기 전에 여러 VIPER 프로젝트를 비교하며 Router의 책임 범위를 확인했다.&lt;/p&gt;
&lt;h2 id="무엇을-확인했나"&gt;무엇을 확인했나&lt;/h2&gt;
&lt;p&gt;분석 기준은 다음 세 가지였다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Router가 현재 ViewController를 어떻게 참조하는가&lt;/li&gt;
&lt;li&gt;화면 전환 시 다음 VIPER 모듈을 누가 조립하는가&lt;/li&gt;
&lt;li&gt;여러 모듈에 걸친 전환을 AppRouter가 담당하는가&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="구현-비교"&gt;구현 비교&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;구현&lt;/th&gt;
&lt;th&gt;모듈 조립&lt;/th&gt;
&lt;th&gt;화면 전환&lt;/th&gt;
&lt;th&gt;AppRouter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/amitshekhariitbhu/iOS-Viper-Architecture"&gt;iOS-Viper-Architecture&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;WireFrame의 정적 메서드&lt;/td&gt;
&lt;td&gt;출발 View를 인자로 전달&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/tailec/ios-architecture"&gt;ios-architecture&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;정적 팩토리 메서드&lt;/td&gt;
&lt;td&gt;전환 사례가 적음&lt;/td&gt;
&lt;td&gt;없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/ferranabello/Viperit"&gt;Viperit&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;프레임워크가 모듈을 관리&lt;/td&gt;
&lt;td&gt;모듈이 직접 자신을 표시&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AppModules&lt;/code&gt;로 모듈 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/giftbott/iOS-Architecture-Sample"&gt;iOS-Architecture-Sample&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;모듈별 생성&lt;/td&gt;
&lt;td&gt;앱 단위 Router가 화면 계층 관리&lt;/td&gt;
&lt;td&gt;싱글톤 AppRouter&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;구현은 달랐지만 공통점도 있었다. View나 Presenter가 직접 다음 화면을 생성하지 않았고, 화면 조립과 전환을 UI 바깥의 객체로 분리하고 있었다.&lt;/p&gt;</description></item><item><title>SniffMEET. UITabBarController VIPER 컨테이너로 다루기</title><link>https://kelly-chui.github.io/posts/sniffmeet-dev-log-viper-tab-bar-container/</link><pubDate>Mon, 11 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/sniffmeet-dev-log-viper-tab-bar-container/</guid><description>&lt;p&gt;VIPER 모듈을 사용하더라도, 직접 탭 바를 구현하지 않는 이상 &lt;code&gt;UITabBarController&lt;/code&gt;는 사용해야 한다. 일반적인 VIPER 화면처럼 View, Presenter, Interactor, Router를 모두 갖춘 독립 모듈로 보기엔 애매한 것 같다.&lt;/p&gt;
&lt;p&gt;특히 Interactor는 여기서 아무 의미가 없어보이고, Router는 &lt;code&gt;UITabBarController&lt;/code&gt;에 내장되어 있으니까&amp;hellip;&lt;/p&gt;
&lt;h2 id="모듈-빌더"&gt;모듈 빌더&lt;/h2&gt;
&lt;p&gt;router, interactor를 생성하고 이를 가지고 있는 presenter를 생성해서 뷰에 집어넣는 방식&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HomeModuleBuilder&lt;/code&gt;는 Home 화면에 필요한 VIPER 구성 요소를 한 곳에서 조립한다. ViewController를 만들고, Router와 Interactor를 생성한 뒤 Presenter에 주입한다. 마지막으로 NavigationFactory를 통해 화면을 &lt;code&gt;UINavigationController&lt;/code&gt;로 감싸서 반환한다.&lt;/p&gt;</description></item><item><title>Software Engineering. VIPER 아키텍처</title><link>https://kelly-chui.github.io/posts/se-viper/</link><pubDate>Mon, 11 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/se-viper/</guid><description>&lt;h2 id="viper란"&gt;VIPER란&lt;/h2&gt;
&lt;img alt="VIPER 구성 요소와 데이터 흐름" loading="lazy" src="https://kelly-chui.github.io/posts/se-viper/image-001-optimized-image.webp"&gt;&lt;p&gt;VIPER는 화면을 View, Interactor, Presenter, Entity, Router로 나누는 아키텍처 패턴이다. 각 객체의 역할과 의존 방향을 제한해 UI, 비즈니스 로직, 화면 전환을 분리한다.&lt;/p&gt;
&lt;h2 id="구성-요소"&gt;구성 요소&lt;/h2&gt;
&lt;h3 id="view"&gt;View&lt;/h3&gt;
&lt;p&gt;화면을 그리고 사용자 입력을 Presenter에 전달한다. Presenter가 전달한 값을 UI에 반영하며, 비즈니스 로직은 직접 처리하지 않는다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;ExampleViewProtocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;AnyObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;displayMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExampleViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UIViewController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="n"&gt;ExamplePresenterProtocol&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;viewDidLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kc"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;viewDidLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;viewDidLoad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;@IBAction&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;buttonTapped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UIButton&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;presenter&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;handleButtonTapped&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;ExampleViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ExampleViewProtocol&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;displayMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;errorLabel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;pre class="mermaid" data-mermaid-source="flowchart&amp;#43;LR%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;View%5B%22View%22%5D&amp;#43;--%3E%7C%22%EC%82%AC%EC%9A%A9%EC%9E%90&amp;#43;%EC%9D%B4%EB%B2%A4%ED%8A%B8%22%7C&amp;#43;Presenter%5B%22Presenter%22%5D%0A&amp;#43;&amp;#43;&amp;#43;&amp;#43;Presenter&amp;#43;-.-%3E%7C%22weak&amp;#43;%C2%B7&amp;#43;%ED%99%94%EB%A9%B4&amp;#43;%EA%B0%B1%EC%8B%A0%22%7C&amp;#43;View"&gt;&lt;/pre&gt;&lt;h3 id="presenter"&gt;Presenter&lt;/h3&gt;
&lt;p&gt;View의 입력을 해석해 Interactor나 Router에 작업을 요청한다. Interactor가 반환한 Entity는 화면에 표시할 값으로 가공해 View에 전달한다.&lt;/p&gt;</description></item><item><title>DevOps. GitHub Actions 워크플로우</title><link>https://kelly-chui.github.io/posts/devops-github-actions-workflow/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-github-actions-workflow/</guid><description>&lt;h2 id="들어가며"&gt;들어가며&lt;/h2&gt;
&lt;p&gt;GitHub Actions는 저장소에서 발생한 이벤트를 기준으로 빌드, 테스트, 배포 같은 작업을 자동화한다. 자동화 과정은 &lt;code&gt;.github/workflows&lt;/code&gt; 디렉토리의 YAML 파일로 정의한다.&lt;/p&gt;
&lt;p&gt;처음 workflow를 작성할 때는 &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;on&lt;/code&gt;, &lt;code&gt;jobs&lt;/code&gt;, &lt;code&gt;steps&lt;/code&gt;가 각각 무엇을 나타내는지부터 이해할 필요가 있다.&lt;/p&gt;
&lt;h2 id="전체-구조"&gt;전체 구조&lt;/h2&gt;
&lt;p&gt;GitHub Actions의 실행 흐름은 다음과 같다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Event -&amp;gt; Workflow -&amp;gt; Job -&amp;gt; Runner -&amp;gt; Step&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;이 흐름을 YAML로 표현하면 다음과 같다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Build and Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;run-name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Build triggered by @${{ github.actor }}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;push&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;pull_request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;macos-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;echo &amp;#34;Build&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;build&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runs-on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;macos-latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;echo &amp;#34;Test&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="name과-run-name"&gt;&lt;code&gt;name&lt;/code&gt;과 &lt;code&gt;run-name&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt;은 workflow 자체의 이름이다. GitHub 저장소의 Actions 탭에서 workflow를 구분할 때 사용한다.&lt;/p&gt;</description></item><item><title>UIKit. TableViewCell 스와이프 동작 넣기</title><link>https://kelly-chui.github.io/posts/ios-uikit-tableviewcell-swipe-actions-uitableviewdelegate/</link><pubDate>Fri, 20 Sep 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-tableviewcell-swipe-actions-uitableviewdelegate/</guid><description>&lt;h2 id="기본-메소드들"&gt;기본 메소드들&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 오른쪽에서 왼쪽으로 스와이프&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;trailingSwipeActionsConfigurationForRowAt&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 왼쪽에서 오른쪽으로 스와이프&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;leadingSwipeActionsConfigurationForRowAt&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="구현-순서"&gt;구현 순서&lt;/h2&gt;
&lt;h3 id="1-uicontextualaction을-사용해서-액션-구현"&gt;1. &lt;code&gt;UIContextualAction&lt;/code&gt;을 사용해서 액션 구현&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deleteAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIContextualAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destructive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;삭제&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 삭제 로직&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="2-uiswipeactionsconfiguration에-액션-등록"&gt;2. &lt;code&gt;UISwipeActionsConfiguration&lt;/code&gt;에 액션 등록&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 액션 여러개 등록 가능&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UISwipeActionsConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;deleteAction&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="3-전체-코드"&gt;3. 전체 코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITableView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trailingSwipeActionsConfigurationForRowAt&lt;/span&gt; &lt;span class="n"&gt;indexPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IndexPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UISwipeActionsConfiguration&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deleteAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIContextualAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destructive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;삭제&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 삭제 로직&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UISwipeActionsConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;deleteAction&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performsFirstActionWithFullSwipe&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="기타"&gt;기타&lt;/h3&gt;
&lt;p&gt;색깔, 이미지 지정 가능&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deleteAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemRed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deleteAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;trash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;performsFirstActionWithFullSwipe&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;true&lt;/code&gt;: 스와이프 하면 첫 번째 액션이 즉시 실행&lt;/li&gt;
&lt;li&gt;&lt;code&gt;false&lt;/code&gt;: 스와이프 된 상태에서 나타는 버튼을 눌러서 액션 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="실제-적용-코드-이슈-트래킹-앱"&gt;실제 적용 코드 (이슈 트래킹 앱)&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITableView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trailingSwipeActionsConfigurationForRowAt&lt;/span&gt; &lt;span class="n"&gt;indexPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IndexPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UISwipeActionsConfiguration&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deleteAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;makeDeleteAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;closeAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;makeCloseAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UISwipeActionsConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;deleteAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;closeAction&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;performsFirstActionWithFullSwipe&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeDeleteAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UIContextualAction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deleteAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIContextualAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destructive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// &lt;/span&gt;&lt;span class="cs"&gt;TODO:&lt;/span&gt;&lt;span class="c1"&gt; 얼럿 띄우고 삭제 로직&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deleteAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;trash&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deleteAction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeCloseAction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UIContextualAction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;closeAction&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIContextualAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// &lt;/span&gt;&lt;span class="cs"&gt;TODO:&lt;/span&gt;&lt;span class="c1"&gt; 이슈 닫기 로직&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;closeAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;archivebox.fill&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;closeAction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;systemIndigo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;closeAction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>UIKit. UIView와 CALayer</title><link>https://kelly-chui.github.io/posts/ios-uikit-uiview-calayer/</link><pubDate>Tue, 17 Sep 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-uiview-calayer/</guid><description>&lt;p&gt;&lt;code&gt;UIView&lt;/code&gt;는 화면의 직사각형 영역을 나타내고, 그 안에 콘텐츠를 관리하는 객체이다. 대부분의 UI 요소가 &lt;code&gt;UIView&lt;/code&gt;를 상속받으며, 화면에 콘텐츠를 보여주고 터치나 제스처를 감지하는 역할을 한다.&lt;/p&gt;
&lt;h2 id="uiview로-콘텐츠-표시하기"&gt;UIView로 콘텐츠 표시하기&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;UIView&lt;/code&gt;는 UIKit에서 제공하는 메소드나 Core Graphics를 이용해 직사각형 영역에 콘텐츠를 그릴 수 있다. 배경색만 있는 간단한 &lt;code&gt;UIView&lt;/code&gt;를 만들어보자.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;magentaRectView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UIView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;magentaRectView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UIView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;magentaRectView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backgroundColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;magenta&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;magentaRectView&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;오토레이아웃 제약은 임의로 정했다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/ios-uikit-uiview-calayer/image-001-optimized-image.webp"&gt;&lt;p&gt;&lt;code&gt;UIView&lt;/code&gt;는 내부에 다른 &lt;code&gt;UIView&lt;/code&gt;를 포함할 수 있다. 상위 뷰에 포함된 뷰를 서브 뷰라고 한다. &lt;code&gt;UIViewController&lt;/code&gt;의 &lt;code&gt;view&lt;/code&gt; 프로퍼티도 &lt;code&gt;UIView&lt;/code&gt; 인스턴스이기 때문에, 위 마젠타 사각형도 &lt;code&gt;UIView&lt;/code&gt; 내부의 &lt;code&gt;UIView&lt;/code&gt;이다. 좀 더 직관적으로 확인하려면, 마젠타 사각형 안에 검은색 사각형을 추가해보자.&lt;/p&gt;</description></item><item><title>UIKit. TableViewCell에 UITextView 넣고 동적으로 높이 변경하기</title><link>https://kelly-chui.github.io/posts/ios-uikit-tableviewcell-uitextview-dynamic-height/</link><pubDate>Sun, 15 Sep 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-tableviewcell-uitextview-dynamic-height/</guid><description>&lt;p&gt;&lt;code&gt;UITableViewCell&lt;/code&gt; 안에 &lt;code&gt;UITextView&lt;/code&gt;를 넣고, 입력되는 텍스트 길이에 따라 셀의 높이가 자동으로 늘어나도록 처리했다.&lt;/p&gt;
&lt;p&gt;처음에는 그냥 &lt;code&gt;UITextView&lt;/code&gt;를 셀에 넣으면 알아서 늘어날 줄 알았는데, &lt;code&gt;UITextView&lt;/code&gt; 자체의 스크롤과 &lt;code&gt;UITableView&lt;/code&gt;의 셀 높이 계산이 같이 걸려 있어서 생각보다 손이 조금 간다ㅏ.&lt;/p&gt;
&lt;p&gt;핵심은 &lt;code&gt;UITextView&lt;/code&gt;의 스크롤을 끄고, 텍스트가 변경될 때 &lt;code&gt;UITableView&lt;/code&gt;에 높이를 다시 계산하라고 알려주는 것이다.&lt;/p&gt;
&lt;h2 id="구현-순서"&gt;구현 순서&lt;/h2&gt;
&lt;h3 id="1-uitextview에서-다음-속성들-체크-해제"&gt;1. &lt;code&gt;UITextView&lt;/code&gt;에서 다음 속성들 체크 해제&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Show Horizontal Indicator&lt;/code&gt;: 텍스트가 가로 크기를 초과한 경우, 가로 스크롤 바 표시&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Show Vertical Indicator&lt;/code&gt;: 텍스트가 세로 크기를 초과한 경우, 세로 스크롤 바 표시&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Scrolling Enabled&lt;/code&gt;: 스크롤 가능 여부 설정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Bounce on Scroll&lt;/code&gt;: 스크롤이 끝에 도달했을 때, 가볍게 튕기는 애니메이션 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="2-nib-등록"&gt;2. &lt;code&gt;Nib&lt;/code&gt; 등록&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UINib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nibName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;GrowingCell&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;forCellReuseIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;GrowingCell&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="3-데이터-소스-추가"&gt;3. 데이터 소스 추가&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;ViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITableViewDataSource&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITableView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numberOfRowsInSection&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITableView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cellForRowAt&lt;/span&gt; &lt;span class="n"&gt;indexPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IndexPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UITableViewCell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;cell&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dequeueReusableCell&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;withIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;GrowingCell&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;indexPath&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;GrowingCell&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;UITableViewCell&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;indexPath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;self&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cell&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="4-델리게이트-작성"&gt;4. 델리게이트 작성&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="nc"&gt;GrowingCellProtocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updateHeightOfRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GrowingCell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITextView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="5-뷰-컨트롤러가-델리게이트-채택하고-구현"&gt;5. 뷰 컨트롤러가 델리게이트 채택하고 구현&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="nc"&gt;ViewController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GrowingCellProtocol&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updateHeightOfRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GrowingCell&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UITextView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;textView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bounds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;newSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sizeThatFits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;greatestFiniteMagnitude&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;newSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UIView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setAnimationsEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;beginUpdates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;endUpdates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UIView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setAnimationsEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;thisIndexPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cell&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tableView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scrollToRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;thisIndexPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;추가. 공식 문서에서는 &lt;code&gt;beginUpdates()&lt;/code&gt; 보다  &lt;code&gt;performBatchUpdates(_:completion:)&lt;/code&gt; 의 사용을 권장하고 있음.&lt;/p&gt;</description></item><item><title>UIKit. Responder Chain</title><link>https://kelly-chui.github.io/posts/ios-uikit-responder-chain/</link><pubDate>Wed, 04 Sep 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-responder-chain/</guid><description>&lt;p&gt;앱에서 터치 입력과 같은 유저 인터랙션을 처리할 때, UIKit은 &lt;code&gt;UIResponder&lt;/code&gt; 객체를 통해 이벤트를 감지하고 적절히 처리한다. 그렇다면 이벤트가 발생했을 때, 어떻게 적절한 &lt;code&gt;UIResponder&lt;/code&gt; 객체를 찾아서 처리할까?&lt;/p&gt;
&lt;p&gt;UIKit에서 이벤트가 어떻게 전달되고 처리되는지, 특히 &lt;code&gt;UIResponder&lt;/code&gt;와 Responder chain의 흐름을 정리했다.&lt;/p&gt;
&lt;h2 id="uiresponder와-uievent"&gt;UIResponder와 UIEvent&lt;/h2&gt;
&lt;p&gt;개발자 문서에서 &lt;code&gt;UIResponder&lt;/code&gt;는 &amp;lsquo;이벤트에 응답하고 처리하기 위한 추상 인터페이스&amp;rsquo;로 소개한다. 여기서 이벤트란, UIKit에서 &lt;code&gt;UIEvent&lt;/code&gt;라는 클래스로 표현되는 단일 유저 인터랙션(예: 터치)을 의미한다. &lt;code&gt;UIEvent&lt;/code&gt; 역시 개발자 문서에서 &amp;lsquo;앱에서 단일 유저 인터랙션을 설명하기 위한 객체&amp;rsquo;라고 정의되어 있다.&lt;/p&gt;</description></item><item><title>UIKit. UIStackView 레이아웃</title><link>https://kelly-chui.github.io/posts/ios-uikit-uistackview/</link><pubDate>Tue, 27 Aug 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-uistackview/</guid><description>&lt;p&gt;&lt;code&gt;UIStackView&lt;/code&gt;는 여러 뷰를 한 방향으로 묶어 배치할 수 있는 컨테이너 뷰다. 직접 서브뷰마다 제약 조건을 하나씩 걸지 않아도, 스택 뷰에 arranged subview로 추가하면 스택 뷰가 내부 뷰들의 배치를 관리한다.&lt;/p&gt;
&lt;p&gt;스택 뷰는 기기의 방향, 화면 크기, 그리고 &lt;code&gt;axis&lt;/code&gt;, &lt;code&gt;alignment&lt;/code&gt;, &lt;code&gt;distribution&lt;/code&gt;, &lt;code&gt;spacing&lt;/code&gt; 같은 프로퍼티를 바탕으로 내부 뷰의 레이아웃을 결정한다.&lt;/p&gt;
&lt;p&gt;이 글에서는 스택 뷰의 주요 프로퍼티가 레이아웃에 어떤 영향을 주는지 정리한다.&lt;/p&gt;
&lt;h2 id="intrinsiccontentsize"&gt;intrinsicContentSize&lt;/h2&gt;
&lt;p&gt;스택 뷰의 레이아웃을 이해하려면 먼저 &lt;code&gt;intrinsicContentSize&lt;/code&gt;를 알아야 한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;intrinsicContentSize&lt;/code&gt;는 뷰가 자신의 내용만을 기준으로 자연스럽게 가지는 크기다. 대표적인 예시는 &lt;code&gt;UILabel&lt;/code&gt;이다.&lt;/p&gt;</description></item><item><title>UIKit. 화면 전환 방식</title><link>https://kelly-chui.github.io/posts/ios-uikit-screen-transitions/</link><pubDate>Wed, 21 Aug 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-screen-transitions/</guid><description>&lt;p&gt;UIKit에서는 화면을 전환하는 방법이 여러 가지 있지만, 실제로는 상황에 따라 적절한 방식을 선택하면 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;화면을 계층적으로 이동한다 → &lt;strong&gt;Show&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Split View의 Detail 화면을 변경한다 → &lt;strong&gt;Show Detail&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;현재 화면 위에 독립적인 화면을 띄운다 → &lt;strong&gt;Present Modally&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;큰 화면에서는 팝오버, 작은 화면에서는 모달로 표시한다 → &lt;strong&gt;Present as Popover&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이번 글에서는 각각의 방식이 어떤 상황에서 사용되는지 간단히 정리해 보려고 한다.&lt;/p&gt;
&lt;h2 id="화면-전환-방식"&gt;화면 전환 방식&lt;/h2&gt;
&lt;h3 id="show"&gt;Show&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;내비게이션 컨트롤러를 사용하는 경우 새로운 뷰 컨트롤러를 &lt;strong&gt;Push&lt;/strong&gt;하여 화면을 전환한다. 사용자가 계층 구조를 따라 이동하는 대부분의 화면 전환이 여기에 해당한다.&lt;/p&gt;</description></item><item><title>DevOps. Git 기초</title><link>https://kelly-chui.github.io/posts/devops-git-overview/</link><pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/devops-git-overview/</guid><description>&lt;h2 id="깃-파일-라이프-사이클"&gt;깃 파일 라이프 사이클&lt;/h2&gt;
&lt;img alt="image.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-git-overview/image-001-optimized-image.webp"&gt;&lt;ol&gt;
&lt;li&gt;Tracked: 관리 대상 파일, 이미 스냅샷에 포함되어 있는 파일 - 깃이 이미 알고 있는 파일들…
&lt;ol&gt;
&lt;li&gt;Unmodified: 수정하지 않은 파일&lt;/li&gt;
&lt;li&gt;Modified: 수정한 파일&lt;/li&gt;
&lt;li&gt;Staged: 커밋으로 저장소에 기록할 파일&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Untracked: 관리 대상이 아닌 파일, 스냅샷 Staging Area에도 포함되지 않은 파일&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt="Screenshot 2024-08-20 at 2.17.11\u202fPM.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-git-overview/image-002-optimized-image.webp"&gt;&lt;p&gt;위 캡처에서&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;test2&lt;/code&gt;: (Staged) 현재 Staging Area에 포함된 파일, 커밋하면 저장소에 기록된다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test&lt;/code&gt;: (Untracked) 트래킹 되지 않은 파일, 스냅샷에도 Staging Area에도 존재하지 않고 워킹 디렉토리에만 존재한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;README&lt;/code&gt;: (Modified) 수정된 파일, 커밋을 하기 위해서는 Staged 상태로 만들어야 함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="파일-새로-추적하기-git-add"&gt;파일 새로 추적하기 (git add)&lt;/h3&gt;
&lt;img alt="Screenshot 2024-08-20 at 2.20.42\u202fPM.png" loading="lazy" src="https://kelly-chui.github.io/posts/devops-git-overview/image-003-optimized-image.webp"&gt;&lt;p&gt;&lt;code&gt;git add&lt;/code&gt; 명령은 파일을 새로 추적할 때도 사용하고, 수정한 파일을 Staged 상태로 만들 때도 사용한다.&lt;/p&gt;</description></item><item><title>UIView와 UIViewController의 차이 + 뷰 생명주기 메소드</title><link>https://kelly-chui.github.io/posts/ios-uikit-uiview-vs-uiviewcontroller-lifecycle/</link><pubDate>Tue, 20 Aug 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/ios-uikit-uiview-vs-uiviewcontroller-lifecycle/</guid><description>&lt;h2 id="공식문서-먼저"&gt;공식문서 먼저&lt;/h2&gt;
&lt;h3 id="uiview"&gt;UIView&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;An object that manages the content for a rectangular area on the screen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;화면의 사각형 영역을 나타내며, 내부에 다른 뷰를 포함할 수 있다. 대부분의 UI 요소가 UIView를 상속받는다.&lt;/li&gt;
&lt;li&gt;콘텐츠를 화면에 나타내고, 사용자의 터치나 제스처를 감지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="uiviewcontroller"&gt;UIViewController&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;An object that manages a view hierarchy for your UIKit app.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;하나 이상의 뷰를 관리하고, 이 뷰들이 사용자와 상호작용하는 방법을 제어한다.&lt;/li&gt;
&lt;li&gt;뷰를 생성하고, 화면에 표시하며, 뷰의 생명 주기를 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="두-줄-요약"&gt;두 줄 요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;UIView는 화면의 직사각형 영역에 표시되는 콘텐츠를 관리하고, 사용자의 동작을 감지하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;UIViewController는 이 UIView를 관리하는 역할을 한다. (사용자의 동작을 감지하면 이 뷰가 어떻게 상호 작용을 해야 할지, UIView 라이프 사이클 관리 등…)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="뷰-라이프-사이클--뷰-컨트롤러-관련-메소드"&gt;뷰 라이프 사이클 + 뷰 컨트롤러 관련 메소드&lt;/h2&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/posts/ios-uikit-uiview-vs-uiviewcontroller-lifecycle/image-001-optimized-image.webp"&gt;&lt;p&gt;순서대로 작성하면&lt;/p&gt;</description></item><item><title>SwiftUI Tutorials. Building Lists and Navigation</title><link>https://kelly-chui.github.io/posts/swiftui-tutorials-02-building-lists-and-navigation/</link><pubDate>Tue, 25 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swiftui-tutorials-02-building-lists-and-navigation/</guid><description>&lt;p&gt;사용자가 전체 랜드마크 목록을 보고 각 위치에 대한 세부 정보를 볼 수 있는 방법을 제공해야 한다.&lt;/p&gt;
&lt;p&gt;모든 랜드마크에 대한 정보를 표시할 수 있는 뷰를 생성하고 사용자가 탭하여 랜드마크에 대한 디테일 뷰를 볼 수 있는 스크롤 목록을 동적으로 생성한다. UI를 미세 조정하고 싶으면 Xcode를 사용하여 다양한 장치 크기에서 미리보기를 렌더링 하면 된다.&lt;/p&gt;
&lt;h2 id="section-1-create-a-landmark-model"&gt;Section 1. Create a landmark model&lt;/h2&gt;
&lt;p&gt;첫 번째 튜토리얼에선, 모든 정보들을 커스텀 뷰에 하드코딩했다. 이제는 뷰로 전달할 수 있는 데이터를 저장하는 모델을 만들 것이다.&lt;/p&gt;</description></item><item><title>SwiftUI Tutorials. Creating and Combining Views</title><link>https://kelly-chui.github.io/posts/swiftui-tutorials-01-creating-and-combining-views/</link><pubDate>Tue, 25 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swiftui-tutorials-01-creating-and-combining-views/</guid><description>&lt;h2 id="section-1-create-a-new-project-and-explore-the-canvas"&gt;Section 1. Create a new project and explore the canvas&lt;/h2&gt;
&lt;p&gt;SwiftUI를 사용하는 새로운 Xcode 프로젝트를 만든다. 캔버스, 미리보기 및 SwiftUI 템플릿 코드를 탐색한다.&lt;/p&gt;
&lt;h3 id="step-1-3"&gt;Step 1-3&lt;/h3&gt;
&lt;p&gt;프로젝트 생성 부분&lt;/p&gt;
&lt;h3 id="step-4"&gt;Step 4&lt;/h3&gt;
&lt;p&gt;SwiftUI 앱 라이프 사이클을 사용하는 앱은 &lt;code&gt;App&lt;/code&gt; 프로토콜을 컨펌하는 스트럭처를 가지고 있다. 스트럭처의 &lt;code&gt;body&lt;/code&gt; 프로퍼티는 디스플레이에 보여줄 컨텐츠를 제공하는 하나 이상의 씬이 있다. &lt;code&gt;@main&lt;/code&gt; 어트리뷰트는 앱의 엔트리 포인트를 지정한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// LandmarksApp.swift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Landmarks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Created by Kelly Chui on 6/25/25.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;SwiftUI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;LandmarksApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;Scene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WindowGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ContentView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="step-5-7"&gt;Step 5-7&lt;/h3&gt;
&lt;p&gt;기본적으로, SwiftUI 뷰 파일은 스트럭처와 프리뷰를 선언한다. 구조체는 &lt;code&gt;View&lt;/code&gt; 프로토콜을 컨펌하며, 뷰의 내용과 레이아웃을 정의한다. &lt;code&gt;preview&lt;/code&gt; 선언은 해당 뷰의 미리보기를 생성한다.&lt;/p&gt;</description></item><item><title>SwiftUI Tutorials. Handling User Input</title><link>https://kelly-chui.github.io/posts/swiftui-tutorials-03-handling-user-input/</link><pubDate>Tue, 25 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swiftui-tutorials-03-handling-user-input/</guid><description>&lt;p&gt;랜드마크 앱에서 사용자는 좋아하는 장소를 플래그하고, 그들이 좋아하는 장소만 필터해서 볼 수 있다. 이런 기능을 만들기 위해서, 리스트에 스위치를 추가하여 유저들이 그들이 좋아하는 장소에만 포커스를 맞출 수 있도록 해야한다. 그리고 별 모양 버튼을 추가하고, 탭하면 유저들이 랜드마크에 favorite 플래그를 할 수 있도록 한다.&lt;/p&gt;
&lt;h2 id="section-1-mark-favorite-landmarks"&gt;Section 1. Mark favorite landmarks&lt;/h2&gt;
&lt;p&gt;리스트를 개선해서 사람들이 한 눈에 favorite를 찾을 수 있도록 시작한다. &lt;code&gt;Landmark&lt;/code&gt; 스트럭처에 프로퍼티를 하나 추가해서, 이 랜드마크가 favorite인지 초기 상태를 읽을 수 있도록 한다. 그리고 favorite 표시된 랜드마크에는 별 아이콘을 보여준다.&lt;/p&gt;</description></item><item><title>BOJ 13144. list of unique numbers</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-13144-list-of-unique-numbers/</link><pubDate>Wed, 12 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-13144-list-of-unique-numbers/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/13144"&gt;https://www.acmicpc.net/problem/13144&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;매우 특이한 유형의 투 포인터 문제다. &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;end&lt;/code&gt;가 증가만 해서는 모든 경우의 수를 나타낼 수 없으며, 모든 경우의 수를 탐색하려면 O(n^2)이 된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1 2 3 1 2&lt;/code&gt; 라는 수열이 있을 때를 생각해보자&lt;/p&gt;
&lt;p&gt;겹치는 원소가 나오지 않도록 작성한 일반적인 투 포인터는 1, 12, 123, 231, 312 이렇게 5번 탐색을 하고 종료한다. 하지만 1 2 3 1 2의 정답은 5가 아니라 15이다. 하지만 이 5번의 탐색만으로도 15라는 결과를 얻을 수 있는데, 우리는 정확한 부분 수열의 형태보다 경우의 수만 알면 되기 때문이다.&lt;/p&gt;</description></item><item><title>BOJ 4179. 불</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-4179-fire/</link><pubDate>Mon, 10 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-4179-fire/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/4179"&gt;https://www.acmicpc.net/problem/4179&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;지훈이가 움직이고, 불을 퍼뜨리면 된다. 순서대로 진행하면 되는데 주의해야 할 점이 두 가지 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1분마다 기준으로 번갈아서 움직여야 한다.&lt;/li&gt;
&lt;li&gt;지훈이가 움직이기 전에 불에 타면 안된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jihun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fires&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;is_jihun_Visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fire_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fire_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fires&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;jihun&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;is_jihun_Visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;jihun&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;jihun&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;jihun_queue&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;fire_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;jihun_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun_temp_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jihun_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;jihun_nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;is_jihun_Visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_jihun_Visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun_temp_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;is_jihun_Visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;is_jihun_Visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;jihun_temp_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jihun_temp_queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fire_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fire_temp_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fire_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fire_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fire_nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;cur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fire_temp_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fire_temp_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fire_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fire_temp_queue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;IMPOSSIBLE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;jihun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;fires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;J&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;jihun&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;F&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fires&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jihun&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fires&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 7490. 0 만들기</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-7490-make-0/</link><pubDate>Mon, 10 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-7490-make-0/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/7490"&gt;https://www.acmicpc.net/problem/7490&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DFS 문제이다. 3가지 연산자 &lt;code&gt;(&amp;quot; &amp;quot;, &amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;)&lt;/code&gt;를 배치하는 모든 경우의 수를 수식으로 만든 후 계산하면 된다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;calcuate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;rawExpression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rawExpression&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rawExpression&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;cal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rawExpression&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;expression&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rawExpression&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replacingOccurrences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;operators&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Character&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;numBuffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;expression&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isNumber&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;numBuffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;operators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;numBuffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;lastNumber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numBuffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;operators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;operators&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;-&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rawExpression&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;calcuate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;+&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;-&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;removeLast&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;seq&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 2668. 숫자고르기</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-2668-number-picking/</link><pubDate>Tue, 04 Jun 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-2668-number-picking/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2668"&gt;https://www.acmicpc.net/problem/2668&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제를 간단하게 표현하면 그래프 내의 사이클을 모두 찾은 다음에, 사이클에 포함되는 노드을 모두 출력하면 된다. 사이클을 찾으려면 그래프내의 모든 노드에서 dfs를 쓰면 되는데 다음과 같은 케이스들로 나눌 수 있겠다.&lt;/p&gt;
&lt;h3 id="1-사이클에-도달하긴-하나-시작-노드는-사이클에-포함되지-않는-케이스"&gt;1. 사이클에 도달하긴 하나 시작 노드는 사이클에 포함되지 않는 케이스&lt;/h3&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/ps/2024/ps-boj-2668-number-picking/image-002-optimized-image.webp"&gt;&lt;p&gt;주어진 예제에서 2번, 4번, 6번, 7번 노드가 해당한다.&lt;/p&gt;
&lt;p&gt;탐색을 시작한 노드에서 사이클에 도달하긴 하나, 시작한 노드는 사이클에 포함되지 않는다. 최적화를 위해 이러한 케이스에도 사이클만 따로 분리해 중복되는 연산을 줄일 수 있겠지만, 이 문제의 n이 큰 수가 아니므로, 그냥 아무런 행동도 하지 않는다.&lt;/p&gt;</description></item><item><title>BOJ 14719. 빗물</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-14719-rainwater/</link><pubDate>Tue, 28 May 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-14719-rainwater/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14719"&gt;https://www.acmicpc.net/problem/14719&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;스택 문제이다. 빗물은 양 옆이 블록으로 막혀있을 때, 낮은 블록의 높이를 기준으로 그 사이에 빗물이 고이게 된다. 따라서 스택을 하나 만들고 인덱스 순서대로 입력받은 다음에, &amp;ldquo;현재까지&amp;rdquo; 가장 높게 쌓여있던 블록의 높이(&lt;code&gt;currentMax&lt;/code&gt;)와 같거나 더 높게 쌓여있는 블록이 스택에 들어오려 할 때, 스택에 쌓여있는 모든 블록들을 빼내면서 고여있는 물의 양을 더하면 된다(&lt;code&gt;currentMax - 중간 블록의 높이&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;하지만 이러한 방법을 쓰면 문제점이 하나 있는데, 블록이 계속 커진다는 보장이 없기 때문에, 마지막에 있는 블록들이 붕 뜨게 된다. 이 때는 스택을 뒤집어서 해결하면 된다. 현재 &lt;code&gt;currentMax&lt;/code&gt;보다 더 큰 수가 앞에 존재하지 않는다면 뒤집힌 스택은 무조건 &lt;code&gt;currentMax&lt;/code&gt;가 마지막에 존재하게 된다. (만약 &lt;code&gt;currentMax&lt;/code&gt;보다 낮은 블록은 이미 pop된 상태일 것이기 때문에) 따라서 스택을 뒤집은 다음(혹은 다른 스택에 차례대로 옮긴 후에) 이 전의 과정을 한번 반복하면 문제가 해결된다.&lt;/p&gt;</description></item><item><title>BOJ 17266. 어두운 굴다리</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-17266-dark-underpass/</link><pubDate>Mon, 06 May 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-17266-dark-underpass/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/17266"&gt;https://www.acmicpc.net/problem/17266&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;가로등 간의 최대 간격을 찾으면 되는 문제이다. 일반적인 가로등 간의 간격과, 시작점과 첫 가로등의 간격, 도착점과 마지막 가로등의 간격을 알아내면 된다.&lt;/p&gt;
&lt;p&gt;가로등 사이의 간격은 양 사이드 모두가 가로등이기 때문에 간격에서 2를 나눠줄 필요가 있다.&lt;/p&gt;
&lt;p&gt;이 문제에는 작은 함정이 하나 있는데, 가로등 사이의 간격이 만약 홀수인 경우에는 2로 나눴을 때 0.5가 내림 되기 때문에 주의해야 한다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;first&lt;/span&gt;&lt;span class="p"&gt;!,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;last&lt;/span&gt;&lt;span class="p"&gt;!)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;interval&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Network. Network 오버뷰</title><link>https://kelly-chui.github.io/posts/cs-network-overview/</link><pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-overview/</guid><description>&lt;h2 id="네트워크"&gt;네트워크&lt;/h2&gt;
&lt;p&gt;노드와 링크(엣지)들이 서로 연결되어 리소스를 공유하는 구조이며, 그래프 형태로 표현할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;노드: 서버, 라우터, 스위치&lt;/li&gt;
&lt;li&gt;링크: 유선 or 무선&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="키워드"&gt;키워드&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;네트워크 토폴로지&lt;/li&gt;
&lt;li&gt;클라이언트와 서버&lt;/li&gt;
&lt;li&gt;패킷&lt;/li&gt;
&lt;li&gt;주소와 전송 방식&lt;/li&gt;
&lt;li&gt;프로토콜&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="네트워크-참조-모델"&gt;네트워크 참조 모델&lt;/h2&gt;
&lt;p&gt;통신이 이루어지는 단계를 계층적으로 표현한 모델&lt;/p&gt;
&lt;h3 id="osi-model"&gt;OSI Model&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;계층&lt;/th&gt;
&lt;th&gt;대표 역할&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;HTTP, DNS 등 네트워크 서비스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Presentation&lt;/td&gt;
&lt;td&gt;인코딩, 압축, 암호화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session&lt;/td&gt;
&lt;td&gt;세션 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transport&lt;/td&gt;
&lt;td&gt;TCP, UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network&lt;/td&gt;
&lt;td&gt;라우팅, IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Link&lt;/td&gt;
&lt;td&gt;같은 LAN에서의 통신&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Physical&lt;/td&gt;
&lt;td&gt;비트 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="tcpip-model"&gt;TCP/IP Model&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;응용 계층(Application Layer): OSI 모델에서 세션, 표현, 응용 계층&lt;/li&gt;
&lt;li&gt;전송 계층(Transport Layer): OSI 모델에서 전송 계층&lt;/li&gt;
&lt;li&gt;인터넷 계층(Internet Layer): OSI 모델에서 네트워크 계층&lt;/li&gt;
&lt;li&gt;네트워크 액세스 계층(Network Access Layer): OSI 모델에서 데이터 링크 계층 (+ 물리 계층)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="캡슐화와-역캡슐화encapsulation-decapsulation"&gt;캡슐화와 역캡슐화(Encapsulation, Decapsulation)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;캡슐화
&lt;ul&gt;
&lt;li&gt;데이터가 계층를 거치면서 헤더가 추가되는 과정, 상위 계층로부터 내려받은 패킷을 페이로드로 하고, 각 계층에 포함된 프로토콜의 헤더나 트레일러를 덧붙이는 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;역캡슐화
&lt;ul&gt;
&lt;li&gt;캡슐화 과정에서 덧붙인 헤더들을 각 계층에서 확인한 뒤, 제거하는 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;각 계층마다 패킷을 부르는 명칭이 다르다.&lt;/p&gt;</description></item><item><title>Network. Physical &amp; Data Link Layer</title><link>https://kelly-chui.github.io/posts/cs-network-physical-data-link-layer/</link><pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-physical-data-link-layer/</guid><description>&lt;h2 id="physical--data-link-layer"&gt;Physical &amp;amp; Data Link Layer&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Physical Layer: 전기, 광, 무선 등의 신호를 통해 데이터를 전송하는 계층&lt;/li&gt;
&lt;li&gt;Data Link Layer: 같은 LAN에서 데이터를 올바르게 전달하기 위한 계층&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="주요-기술"&gt;주요 기술&lt;/h2&gt;
&lt;h3 id="ethernet"&gt;Ethernet&lt;/h3&gt;
&lt;p&gt;같은 LAN 안에서 데이터를 주고받는 대표적인 기술이다.&lt;/p&gt;
&lt;h4 id="ethernet-frame"&gt;Ethernet Frame&lt;/h4&gt;
&lt;p&gt;이더넷 기반의 네트워크에서 주고받는 프레임, 프리앰블, 송 · 수신 MAC 주소, 타입/길이, 데이터, FCS로 구성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;프리앰블(preamble)
&lt;ul&gt;
&lt;li&gt;8 Bytes&lt;/li&gt;
&lt;li&gt;이더넷 프레임을 수신하고 있다는 것을 알려주는 부분&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MAC 주소(MAC address)
&lt;ul&gt;
&lt;li&gt;12(6 + 6) Bytes&lt;/li&gt;
&lt;li&gt;이더넷 프레임을 송 · 수신할 장치의 MAC 주소를 가지고 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;타입/길이(type/length)
&lt;ul&gt;
&lt;li&gt;2 Bytes&lt;/li&gt;
&lt;li&gt;1500 이상의 값일 경우에는 프로토콜의 타입을 뜻함&lt;/li&gt;
&lt;li&gt;1500 이하의 경우엔 LLC라는 값으로 타입 판별한다. 하지만 요즘은 거의 대부분 Ethernet II를 사용하기 때문에 명확하게 타입으로 사용함.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터(data)
&lt;ul&gt;
&lt;li&gt;최대 1500Bytes&lt;/li&gt;
&lt;li&gt;실제로 송수신할 데이터&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FCS
&lt;ul&gt;
&lt;li&gt;프레임의 오류가 있는지 여부를 확인하기 위한 트레일러&lt;/li&gt;
&lt;li&gt;CRC(Cyclic redundancy check)라는 오류 검출용 값이 명시됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="wireless"&gt;Wireless&lt;/h3&gt;
&lt;p&gt;유선이 아닌 전파로 통신하는 방법이다. 대표적으로 와이파이가 있다. 주파수 간섭 문제를 최소화 하기 위해 채널이라는 하위 주파수 대역으로 세분화한다.&lt;/p&gt;</description></item><item><title>BOJ 14890. 경사로</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-14890-slope/</link><pubDate>Fri, 19 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-14890-slope/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14890"&gt;https://www.acmicpc.net/problem/14890&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;경사로의 방향을 생각해보면 왼쪽에서 오른쪽으로 올라가는 방향이 있을 것이고, 그 반대인 오른쪽에서 왼쪽으로 올라가는 방향도 있을 것이다. 이러한 경우에는 한 번에 해결하기 보다는 배열을 정방향, 역방향으로 각각 순회하여 경사로를 만들어주는 것이 좋다.&lt;/p&gt;
&lt;p&gt;따라서 알고리즘은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;주어진 2차원 배열을 Transpose한 배열을 하나 더 만든다. 세로 모양의 길을 찾기 위해서이다.&lt;/li&gt;
&lt;li&gt;정방향으로 우선 순회한다. 다음에 있는 칸의 높이가 현재 칸보다 같으면 &lt;code&gt;count&lt;/code&gt;를 하나 늘리고(&lt;code&gt;count&lt;/code&gt;는 경사로를 지을 수 있는지 판단할 때 사용한다.) 1 낮으면 일단은 패스(역방향에서 확인한다), 1 높으면 경사로를 설치할 수 있는지 판단한다.&lt;/li&gt;
&lt;li&gt;경사로를 설치할 수 있는지 판단하는 기준은 두 가지이다. 일단 경사로를 설치하기 충분한 공간이 확보되었는가 (&lt;code&gt;count&lt;/code&gt;로 충분한 공간이 얼마나 있는지를 알 수 있다.), 만약 가능하다면 이미 그곳에 경사로가 설치되어 있지는 않는가(이는 &lt;code&gt;is_built&lt;/code&gt; 배열로 추적한다. 하지만 정방향을 먼저 하므로 지금 상황에선 필요 없다.)&lt;/li&gt;
&lt;li&gt;역방향으로 순회한다. 정방향과 같지만 정방향을 순회하면서 경사로를 지은 곳을 유의할 필요가 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;is_built&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;is_built&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_built&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;is_built&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;current_height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph_tranposed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph_tranposed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph_tranposed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 14891. 톱니바퀴</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-14891-gears/</link><pubDate>Fri, 19 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-14891-gears/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14891"&gt;https://www.acmicpc.net/problem/14891&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;상황 설명이 굉장히 난해하고 비직관적이므로 글을 잘 읽어야 한다. 문제를 겨우 이해하고 나면 알고리즘이나 구현 능력 자체는 크게 요구하지 않는다. 글을 이해하는것 자체가 이 문제의 가장 큰 난관이다.&lt;/p&gt;
&lt;p&gt;이 문제에서 톱니바퀴는 현실의 톱니바퀴처럼 움직이지 않는다. 이전 톱니바퀴가 회전하면 다음 톱니바퀴도 회전해야할지 말아야 할지를 이미 돌아간 상태의 이전 톱니바퀴가 아닌 돌기 전의 이전 톱니바퀴의 상태로 판단해야 한다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Gear&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__stat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__top&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__left&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__right&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nd"&gt;@property&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;top&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__stat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__top&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nd"&gt;@property&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__stat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__left&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nd"&gt;@property&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__stat&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;left_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gear_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cur_gear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gear_num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;next_gear&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gear_num&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;gears&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_gear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;gears&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur_gear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rotate_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;next_gear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_drct&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cur_gear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next_gear&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_drct&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;right_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gear_num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cur_gear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gear_num&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;next_gear&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gear_num&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;gears&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_gear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;gears&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur_gear&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rotate_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;next_gear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_drct&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cur_gear&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next_gear&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_drct&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;gear1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;gear2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;gear3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;gear4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Gear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;gears&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gear1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gear2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gear3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gear4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rotate_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rotate_queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;left_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;right_shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rotate_queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gears&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rotate_queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;gears&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;rank&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rank&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 14499. 주사위 굴리기</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-14499-dice-rolling/</link><pubDate>Mon, 15 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-14499-dice-rolling/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14499"&gt;https://www.acmicpc.net/problem/14499&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;특별한 알고리즘이나 문제 해결 기법을 사용할 필요 없이, 순수하게 딕셔너리 자료구조만을 사용해서 풀 수 있는 문제이다.&lt;/p&gt;
&lt;p&gt;주어진 주사위의 전개도를 이용하여 각 면에 숫자를 붙이고(면에 써져있는 숫자가 아닌 각 면을 인식하게 해주는 숫자, 이하 ID숫자라고 하겠다.) 이를 방향: ID 숫자의 꼴로 딕셔너리를 생성한다.&lt;/p&gt;
&lt;p&gt;또 ID숫자: 면에 적힌 숫자 꼴로 딕셔너리를 하나 더 생성하여 두개의 딕셔너리로 주사위의 방향과 각 면에 적혀있는 숫자를 추적할 수 있다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;copy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;north&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ori&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ori&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;south&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ori&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ori&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;east&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ori&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ori&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;west&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ori&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ori&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dice_num&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dice_num&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dice_num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;l&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;n&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;w&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;east&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;west&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;north&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;south&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isTrue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dice_num&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dice_drct&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;u&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 12100. 2048(Easy)</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-12100-2048-easy/</link><pubDate>Sun, 14 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-12100-2048-easy/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/12100"&gt;https://www.acmicpc.net/problem/12100&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;최대 20 * 20 크기의 보드에서 2048 게임을 하는 것이다. 최대 5번의 이동만 한다고 문제에 주어져 있으므로, 모든 경우를 탐색하여 문제를 풀 수 있다.&lt;/p&gt;
&lt;p&gt;이 문제에서 주의해야할 점은 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이동하는 방향에서 가까운 숫자부터 이동해야한다.&lt;/li&gt;
&lt;li&gt;한 번의 이동동안 이미 합쳐진 숫자는 다시 합쳐지지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 두가지 조건만 잘 생각하면서 작성하면 된다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;currentGraph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentGraph&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isMerged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;]](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;newRow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;newRow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newRow&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;newColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;newColumn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isMerged&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newColumn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;graph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 13460. 구슬 탈출 2</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-13460-marble-escape-2/</link><pubDate>Sat, 13 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-13460-marble-escape-2/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/13460"&gt;https://www.acmicpc.net/problem/13460&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;기울이는 방향에 따라서 구슬이 이동하므로, 구슬이 이동할 수 있는 방향은 상하좌우임을 알 수 있다. 이 때, 한 번 기울일 때 마다 구슬의 최종 위치는 하나가 나오므로, BFS를 이용해서 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;문제의 조건을 정리하면 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;한 칸에는 구슬 한 개만 들어갈 수 있다.&lt;/li&gt;
&lt;li&gt;한 번 기울이면 구슬이 더 이상 움직이지 못할 때 까지 움직인다.&lt;/li&gt;
&lt;li&gt;10번 이하의 횟수로만 기울인다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;1, 2 조건을 조합하면 구슬이 다른 구슬을 만나도 벽을 만난것과 같음을 알 수 있고, 따라서 구슬이 겹친 경우에는 처리를 해줘야 한다.&lt;/p&gt;</description></item><item><title>BOJ 10021. watering the fields</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-10021-watering-the-fields/</link><pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-10021-watering-the-fields/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/10021"&gt;https://www.acmicpc.net/problem/10021&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;&amp;ldquo;모든 필드를 파이프 네트워크로 연결하는 데 필요한 최소 금액&amp;quot;에서 MST 문제임을 알았다. 크루스칼 알고리즘을 쓰면 쉽게 풀릴 문제다.&lt;/p&gt;
&lt;p&gt;우선 각 노드간의 거리를 알 수 없으므로 모든 경우의 수를 계산해야 한다. 필드의 개수가 2000개 이하이므로 O(n^2)의 연산을 해도 충분하다.&lt;/p&gt;
&lt;p&gt;그 이후에는 크루스칼 알고리즘을 적용하면 되는데, 제약조건 중 하나가 비용이 C 미만인 파이프는 만들지 않는다는 것이다. 따라서 두 노드간 거리가 C 미만인 엣지는 존재하지 않는 것으로 해야한다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;squared_euclidean_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;mapping&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yi&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;squared_euclidean_length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;mapping&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 15591. mootubesliver</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-15591-mootubesliver/</link><pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-15591-mootubesliver/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/15591"&gt;https://www.acmicpc.net/problem/15591&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;문제가 복잡하게 설명되어 있다. 중요한 것은 모든 노드가 연결되어 있고 웨이트를 가진 엣지가 존재하지만, 두 노드간의 거리는 경로상의 가장 작은 웨이트를 가진 엣지가 된다.&lt;/p&gt;
&lt;p&gt;따라서 웨이트가 있다 해서 다익스트라를 쓸 필요가 없다. 들어오는 쿼리마다 BFS를 이용하여 그래프를 탐색하고 두 노드간의 거리는 실시간으로 업데이트 해주면 된다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;987_654_321&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cur_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cur_usado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_usado&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cur_node&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cur_usado&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;next_usado&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;next_usado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cur_usado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;next_usado&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next_usado&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_node&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;qi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ri&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;qi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ri&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;qi&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;qi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ri&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;qi&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ri&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 5558. チ ズ cheese</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-5558-cheese/</link><pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-5558-cheese/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/5558"&gt;https://www.acmicpc.net/problem/5558&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="파파고-번역"&gt;파파고 번역&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;올해도 JOI 마을의 치즈 공장이 치즈 생산을 시작하여, 쥐들이 둥지에서 얼굴을 내밀었다. JOI 마을은 동서남북으로 구획 정리되어 있고, 각 구획은 둥지, 치즈 공장, 장애물, 공터 중 하나이다. 쥐들은 둥지에서 출발하여 모든 치즈 공장을 방문 하여 치즈를 한 개씩 먹는다.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;이 마을에는 N개의 치즈 공장이 있는데, 모든 공장이 한 종류의 치즈만을 생산한다. 치즈의 단단함은 공장마다 다르고 단단함도 다르다 1부터 N까지의 치즈를 생 산하는 치즈공장이 마침 하나씩 있다.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;증가
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;쥐들의 첫 번째 체력은 1이고, 치즈를 한 개 먹을 때마다 그들의 체력은 1증가 하지만, 쥐들은 자신의 체력보다 더 단단한 치즈를 먹을 수는 없다.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;쥐는 동서남북으로 이웃한 구역으로 1분이면 이동할 수 있지만, 장애물 구역에는 들어갈 수 없다. 치즈 공장을 치즈를 먹지 않고 지나갈 수도 있다. 치즈를 다 먹을 때까지 걸리는 가장 짧은 시간을 요구하는 프로그램을 작성하라. 쥐가 치즈를 먹 는 데 걸리는 시간은 무시할 수 없다.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="풀이"&gt;풀이&lt;/h3&gt;
&lt;p&gt;처음에 문제를 읽었을 땐, 치즈를 먹는 순서를 어떻게 정해야 하나 싶었지만, 시작 할 때 쥐의 체력이 1 고정이므로 고민할 필요 없이 1, 2, 3, &amp;hellip;, N 순서대로 먹으면 된다.&lt;/p&gt;</description></item><item><title>BOJ 14226. 이모티콘</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-14226-emoticon/</link><pubDate>Tue, 09 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-14226-emoticon/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14226"&gt;https://www.acmicpc.net/problem/14226&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;현재 상태를 나타내는 변수를 화면에 있는 이모티콘의 개수, 클립보드에 저장되어 있는 이모티콘의 개수로 나타낼 수 있다. 각각의 연산이 모두 1초가 걸리므로 BFS를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;BFS를 사용하려면 노드에 방문했는지를 판별할 방법이 필요한데, 여기에선 &lt;code&gt;Array&lt;/code&gt;보다는 &lt;code&gt;Set&lt;/code&gt;을 쓰는것이 효율적이다. 두 개의 정수가 노드를 구성하므로 2차원 배열을 만들면 되겠지만, 이런 방식으로 한다면 배열의 크기가 너무 커질 뿐더러 효율적인 배열의 크기를 정하기도 머리가 복잡해진다. 따라서 방문한 노드를 &lt;code&gt;Set&lt;/code&gt;에 저장해서 &lt;code&gt;contains()&lt;/code&gt;함수로 방문 여부를 판단하는 방식을 이용한다.&lt;/p&gt;</description></item><item><title>BOJ 10159. 저울</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-10159-scale/</link><pubDate>Sun, 07 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-10159-scale/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/10159"&gt;https://www.acmicpc.net/problem/10159&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;노드간의 연결 여부를 따지는 따지는 문제이므로 처음에는 단순히 Union-Find Set을 사용하면 될 줄 알았다. 하지만 물건 A와 B의 관계가 있을 때 가능한 경우의 수는 &amp;lsquo;A가 B보다 무겁다&amp;rsquo; 혹은 &amp;lsquo;B가 A보다 무겁다&amp;rsquo; 두 가지의 경우가 있으므로 방향 그래프 가 된다. 따라서 Union-Find Set을 사용하는 것 보다는 방향 그래프에서도 적용 가능한 알고리즘을 사용해야 한다. (아래의 코드에서 엣지의 방향은 무거운 쪽에서 가벼운 쪽으로 했으며. 반대로 해도 상관 없다.)&lt;/p&gt;
&lt;p&gt;문제에서 각 물건에 따라서 그 물건과의 비교 결과를 알 수 없는 물건의 개수를 출력하라고 했기 때문에, 노드에서 다른 노드로 가는 모든 경우의 수를 알아야 한다. 따라서 다익스트라 알고리즘을 n번 쓰거나 플로이드-워셜 알고리즘을 한 번만 쓰면 된다.&lt;/p&gt;</description></item><item><title>BOJ 14658. 하늘에서 별똥별이 빗발친다</title><link>https://kelly-chui.github.io/ps/2024/ps-boj-14658-shooting-stars/</link><pubDate>Sun, 07 Apr 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2024/ps-boj-14658-shooting-stars/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14658"&gt;https://www.acmicpc.net/problem/14658&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;우선 최악의 경우를 생각해보자. N, M이 각각 500,000 이고, L은 1, K가 100일 때가 최악인 경우가 된다. 이 상태에서 모든 경우의 수를 확인하려면 별의 위치를 250,000,000,000,000번 확인해야 한다. 따라서 모든 경우의 수를 판단하는건 불가능 하다.&lt;/p&gt;
&lt;p&gt;따라서 트램펄린을 설치할 위치를 합리적으로 정해야 한다. 주어진 조건을 보면 별이 최대 100개 까지밖에 없으므로 이를 활용하여 생각해본다.&lt;/p&gt;
&lt;p&gt;우선 별 하나를 기준으로 보면 L * L 크기의 트램펄린이고, 별이 최대 100개 있으므로 확인해야 할 위치는 최악의 경우에 100,000,000,000,000개 이다. 사실상 위의 경우와 다를바가 없으므로 불가능하다.&lt;/p&gt;</description></item><item><title>Combine. Combine in Practice - WWDC19</title><link>https://kelly-chui.github.io/posts/wwdc-combine-in-practice/</link><pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-combine-in-practice/</guid><description>&lt;h2 id="a-unified-declarative-api-for-processing-values-over-time"&gt;A unified, declarative API for processing values over time&lt;/h2&gt;
&lt;p&gt;Combine에서는 값이 시간의 흐름에 따라 전달되는 과정을 Publisher로 표현하고, 여러 연산자를 연결해 데이터가 변환되는 흐름을 선언적으로 작성한다. 아래 예제에서는 Notification으로 전달된 Data를 &lt;code&gt;MagicTrick&lt;/code&gt;으로 디코딩한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trickNamePublisher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NotificationCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newTrickDownloaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Output: Data, Failure: Never&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;decoder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicTrick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Output: MagicTrick, Failure: Error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;decode&lt;/code&gt; 연산자를 사용하면 위 변환을 다음과 같이 줄여서 작성할 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trickNamePublisher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NotificationCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newTrickDownloaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Output: Data, Failure: Never&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicTrick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// Output: MagicTrick, Failure: Error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="error-handling"&gt;Error Handling&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;모든 Publisher는 자신이 발생시킬 수 있는 실패의 종류를 명확하게 정의한다.&lt;/li&gt;
&lt;li&gt;실패가 발생하지 않거나 이미 처리된 경우에는 &lt;code&gt;Never&lt;/code&gt;를 Failure 타입으로 사용한다.&lt;/li&gt;
&lt;li&gt;Combine은 실패를 감지하고 복구할 수 있는 다양한 연산자를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Combine의 Publisher는 전달하는 값의 타입인 &lt;code&gt;Output&lt;/code&gt;과 실패할 때 전달하는 오류의 타입인 &lt;code&gt;Failure&lt;/code&gt;를 함께 가진다. 두 타입이 연산자를 거치며 어떻게 바뀌는지 확인하면 데이터 흐름과 오류 흐름을 함께 추적할 수 있다.&lt;/p&gt;</description></item><item><title>Combine. Introducing Combine - WWDC19</title><link>https://kelly-chui.github.io/posts/wwdc-combine-introducing-combine/</link><pubDate>Sun, 17 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-combine-introducing-combine/</guid><description>&lt;h2 id="combine"&gt;Combine&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Customize handling of asynchronous events by combining event-processing operators.&lt;/p&gt;
&lt;p&gt;결합된 이벤트 처리 연산자를 이용하여 비동기 이벤트 처리를 커스터마이즈 하는 방법&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Combine은 데이터 흐름을 간편하게 처리하고 비동기 이벤트를 관리하기 위한 프레임워크다. 다양한 소스에서 발생하는 이벤트를 같은 방식으로 다루고, 이벤트 사이의 상호작용을 연산자로 조합할 수 있다.&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Generic: 제네릭을 사용해 다양한 타입의 데이터 흐름을 표현한다.&lt;/li&gt;
&lt;li&gt;Type safe: Publisher의 출력 타입과 실패 타입을 컴파일 타임에 확인한다.&lt;/li&gt;
&lt;li&gt;Composition first: 작은 Publisher와 연산자를 조합해 더 큰 흐름을 만든다.&lt;/li&gt;
&lt;li&gt;Request driven: Subscriber가 필요한 만큼의 값을 요청하는 방식으로 흐름을 제어한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="핵심-개념"&gt;핵심 개념&lt;/h2&gt;
&lt;h3 id="publisher"&gt;Publisher&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;값과 에러가 어떻게 생성되는지를 정의한다.&lt;/p&gt;</description></item><item><title>Network. HTTP(HyperText Transfer Protocol)</title><link>https://kelly-chui.github.io/posts/cs-network-http/</link><pubDate>Thu, 14 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-http/</guid><description>&lt;h2 id="http"&gt;HTTP&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;HTTP: HyperText Transfer Protocol&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;HTTP는 웹에서 클라이언트와 서버가 데이터를 주고받기 위한 애플리케이션 계층 프로토콜이다.&lt;/p&gt;
&lt;p&gt;클라이언트가 요청(Request)을 보내면 서버가 응답(Response)을 반환하는 Request-Response 방식으로 동작한다.&lt;/p&gt;
&lt;h2 id="동작-방식"&gt;동작 방식&lt;/h2&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;↓ HTTP Request
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Server
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;↓ HTTP Response
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Client&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Request-Response 방식으로 동작한다.&lt;/li&gt;
&lt;li&gt;Stateless를 기본으로 한다.&lt;/li&gt;
&lt;li&gt;HTTP/1.x와 HTTP/2는 TCP를 기반으로 동작한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="버전별-변화"&gt;버전별 변화&lt;/h2&gt;
&lt;h3 id="http10"&gt;HTTP/1.0&lt;/h3&gt;
&lt;p&gt;기본적으로 요청마다 연결을 새로 만드는 방식이 널리 사용됐다. 서버에서 여러 파일을 가져올 때 TCP 연결을 반복해서 설정하면 지연이 커질 수 있다. 다만 HTTP/1.0에서도 &lt;code&gt;Connection: keep-alive&lt;/code&gt;를 확장 기능으로 사용할 수 있었다.&lt;/p&gt;</description></item><item><title>Network. 네트워크 기기</title><link>https://kelly-chui.github.io/posts/cs-network-network-devices/</link><pubDate>Thu, 14 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-network-devices/</guid><description>&lt;h2 id="네트워크-기기의-처리-범위"&gt;네트워크 기기의 처리 범위&lt;/h2&gt;
&lt;p&gt;네트워크 장비는 주로 어떤 계층의 정보를 보고 전달 여부를 결정하는지에 따라 구분한다. 실제 장비는 여러 계층의 기능을 함께 제공할 수 있으므로 아래 구분은 대표적인 처리 기준이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;애플리케이션 계층: L7 스위치&lt;/li&gt;
&lt;li&gt;인터넷 계층: 라우터, L3 스위치&lt;/li&gt;
&lt;li&gt;데이터 링크 계층: L2 스위치, 브리지&lt;/li&gt;
&lt;li&gt;데이터 링크·물리 계층: NIC, 무선 AP&lt;/li&gt;
&lt;li&gt;물리 계층: 리피터&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="애플리케이션-계층을-처리하는-기기"&gt;애플리케이션 계층을 처리하는 기기&lt;/h2&gt;
&lt;p&gt;애플리케이션 계층의 정보를 기반으로 트래픽을 처리하는 장비&lt;/p&gt;
&lt;h3 id="l7스위치로드-밸런서"&gt;L7스위치(로드 밸런서)&lt;/h3&gt;
&lt;p&gt;HTTP 헤더, URL 경로, 쿠키처럼 애플리케이션 계층의 정보를 읽어 요청을 적절한 백엔드 서버로 분산하는 장비 또는 소프트웨어&lt;/p&gt;</description></item><item><title>TCP/IP 4계층</title><link>https://kelly-chui.github.io/posts/cs-network-tcp-ip-layer-4/</link><pubDate>Wed, 13 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/cs-network-tcp-ip-layer-4/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;TCP/IP 4계층은 OSI 7계층과 더불어 인터넷에서 데이터를 주고받기 위해 사용하는 대표적인 네트워크 참조 모델이다.&lt;/p&gt;
&lt;p&gt;네트워크 통신 과정을 역할에 따라 계층으로 분리하여 관리하며, 각 계층은 독립적인 역할을 수행한다.&lt;/p&gt;
&lt;p&gt;덕분에 특정 계층의 구현이 변경되더라도 다른 계층에 미치는 영향을 최소화할 수 있다.&lt;/p&gt;
&lt;h2 id="계층-구성"&gt;계층 구성&lt;/h2&gt;
&lt;h3 id="애플리케이션application"&gt;애플리케이션(Application)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;대표 프로토콜: HTTP, HTTPS, DNS, FTP, SMTP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;응용 프로그램이 사용되는 프로토콜 계층 이메일, 웹 서비스 등 서비스를 실질적으로 제공&lt;/p&gt;
&lt;h3 id="전송transport"&gt;전송(Transport)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;대표 프로토콜: TCP, UDP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;송신자와 수신자 간의 데이터 전송을 담당하는 계층&lt;/p&gt;</description></item><item><title>Swift. Meta Type</title><link>https://kelly-chui.github.io/posts/swift-meta-type/</link><pubDate>Fri, 26 Jan 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/swift-meta-type/</guid><description>&lt;h2 id="소개"&gt;소개&lt;/h2&gt;
&lt;p&gt;메타 타입은 이러한 타입 자체를 값으로 다루기 위한 타입이다.&lt;/p&gt;
&lt;p&gt;즉, 인스턴스가 아니라 타입 그 자체를 표현하는 타입이라고 생각하면 된다.&lt;/p&gt;
&lt;h2 id="종류"&gt;종류&lt;/h2&gt;
&lt;h3 id="type"&gt;&lt;code&gt;.Type&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;구조체, 클래스, 열거형 등 구체적인 타입의 메타 타입이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id="protocol"&gt;&lt;code&gt;.Protocol&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;프로토콜 자체의 메타 타입이다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;AnyObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;Protocol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;AnyObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="언제-사용할까"&gt;언제 사용할까?&lt;/h2&gt;
&lt;p&gt;메타 타입은 생각보다 자주 등장한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;타입 자체를 함수의 인자로 전달할 때&lt;/li&gt;
&lt;li&gt;런타임에 타입을 비교하거나 확인할 때&lt;/li&gt;
&lt;li&gt;타입 정보를 저장해야 할 때&lt;/li&gt;
&lt;li&gt;&lt;code&gt;type(of:)&lt;/code&gt;를 사용할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="필요한-이유"&gt;필요한 이유&lt;/h2&gt;
&lt;p&gt;메타 타입이 필요한 가장 큰 이유는 타입 자체를 값처럼 다루기 위해서이다.&lt;/p&gt;</description></item><item><title>BOJ 17298. 오큰수</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-17298-next-greater-element/</link><pubDate>Mon, 10 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-17298-next-greater-element/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/17298"&gt;https://www.acmicpc.net/problem/17298&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;스택을 이용하는 문제이다. &lt;a href="https://junmusu.tistory.com/122"&gt;2493번 문제&lt;/a&gt;와 사실상 같은 문제인데, 배열이 뒤집혀 있다는 것과 인덱스가 아닌 해당 인덱스에 대응하는 값을 사용하는 것이 다르다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;h4 id="swift"&gt;Swift&lt;/h4&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;isEmpty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;last&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;removeLast&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;last&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;last&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="n"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;joined&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id="c"&gt;C++&lt;/h4&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nl"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;answerIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;answerIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;answerIndex&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;answerIndex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 2293. 동전 1</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-2293-coin-1/</link><pubDate>Mon, 10 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-2293-coin-1/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2293"&gt;https://www.acmicpc.net/problem/2293&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;DP를 사용하는 문제이다. dp 테이블의 각 인덱스가 해당 인덱스 만큼의 가치를 만들 수 있는 경우의 수 라고 하면 쉽게 풀 수 있다.&lt;/p&gt;
&lt;p&gt;동전의 가치를 &lt;code&gt;value&lt;/code&gt;라고 하면 그 동전을 하나 추가해서 &lt;code&gt;i&lt;/code&gt;만큼의 가치를 만들 수 있는 경우의 수는 &lt;code&gt;dp[i] += dp[i - value]&lt;/code&gt; 라고 할 수 있다. 따라서 하나의 가치에 대해서 동전의 종류의 수 만큼 반복문을 돌려야 한다.&lt;/p&gt;
&lt;p&gt;문제에서 주어진 또 다른 조건은 경우의 수가 2의 31제곱이 넘지 않는다는 것이다. 또한 스위프트에서는 오버플로우를 방지하기 위해 2의 31제곱이 넘어가는 수를 다 제거해줘야 한다. (최종적으로 출력할 결과가 2의 31제곱이 넘어가지 않으므로 중간에 2의 31제곱이 넘는 값은 자연스럽게 쓸모가 없는 값이 된다.)&lt;/p&gt;</description></item><item><title>BOJ 2493. 탑</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-2493-towers/</link><pubDate>Mon, 10 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-2493-towers/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2493"&gt;https://www.acmicpc.net/problem/2493&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;스택을 사용하면 쉽게 풀 수 있는 문제이다. 각 탑에서 왼쪽에 신호를 발사하므로, 현재 인덱스보다 앞에 있는 인덱스중 가장 먼저 나오는 값이 더 큰 인덱스를 찾으면 된다.&lt;/p&gt;
&lt;p&gt;현재 인덱스의 탑과 스택의 top에 있는 인덱스의 탑을 비교한다. top 인덱스의 탑이 더 크면 이 인덱스에 있는 탑은 처음으로 신호를 받는 탑이므로, &lt;code&gt;answer&lt;/code&gt; 배열에 추가한다. 그렇지 않다면, 해당 인덱스에 있는 탑은 신호를 받지 못하는 탑 이므로 스택에서 제거한다. 현재 인덱스가 다음 인덱스들의 신호를 받을 수 있으므로 스택에 현재 인덱스를 추가한다.&lt;/p&gt;</description></item><item><title>BOJ 1939. 중량 제한</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-1939-weight-limit/</link><pubDate>Fri, 07 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-1939-weight-limit/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1939"&gt;https://www.acmicpc.net/problem/1939&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;섬(노드)들과 다리(엣지)로 이루어진 그래프가 주어지고, 그 다리들 사이를 지나 목표 노드에 도착해야 한다.&lt;/p&gt;
&lt;p&gt;다리에 웨이트가 존재하지 않고 (중량 제한은 엣지가 유효한지 판단하는 기준일 뿐 엣지의 웨이트랑 관련 없다) 최단 거리를 구하는 문제도 아니므로, 다익스트라 알고리즘이 아닌 BFS를 이용해 탐색할 수 있다.&lt;/p&gt;
&lt;p&gt;중량이 늘어날수록 건널 수 있는 다리가 적어진다(엣지가 비활성화 된다). 우리는 이 때 주어진 두 섬 중 하나의 섬에서 다른 하나의 섬으로 갈 수 있는 최대의 중량을 구하면 된다. 리니어 서치로도 결과를 구할 수야 있겠지만 현실적으로 1 - 1,000,000,000 값을 다 탐색하는건 너무 비효율적이기 때문에 바이너리 서치를 하면 된다.&lt;/p&gt;</description></item><item><title>BOJ 1520. 내리막 길</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-1520-downhill-path/</link><pubDate>Thu, 06 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-1520-downhill-path/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1520"&gt;https://www.acmicpc.net/problem/1520&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;dfs를 이용하면 쉽게 풀 수 있는 문제일 것 같지만, 주어지는 그래프의 크기가 커서 시간초과가 나오는 문제이다. 하지만 이러한 문제들은 중첩되는 연산이 많으므로 DP를 이용하면 시간초과 없이 해결할 수 있는 경우가 흔하다.&lt;/p&gt;
&lt;p&gt;DP의 컨셉은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;그래프의 특정 칸에서 목적지로 도착하는 경우의 수는 앞선 경로에 상관없이 항상 같다.&lt;/li&gt;
&lt;li&gt;따라서 각 칸에서 목적지로 가는 경로의 수를 dp테이블에 메모이제이션 한다면 불필요한 연산을 하지 않아도 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;따라서 점화식을 dp[x][y] = dp[x - 1][y] + dp[x + 1][y] + dp[x][y - 1] + dp[x][y + 1]로 일반화 할 수 있다. 각 항에서 탐색이 불가능한 칸((x, y)보다 높은 칸, 존재하지 않는 칸) 에 대응되는 항은 제외해야하기 때문에 엄밀히 말해서는 틀리지만, 이해하는데는 충분하다.&lt;/p&gt;</description></item><item><title>BOJ 16234. 인구 이동</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-16234-population-movement/</link><pubDate>Thu, 06 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-16234-population-movement/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/16234"&gt;https://www.acmicpc.net/problem/16234&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;그래프 각 원소를 전체 탐색하며, BFS를 수행하는 문제이다. 탐색할 수 있는 칸에 대한 제약조건이 문제에 제시되므로, 이에 따라 BFS를 수행하면 된다.&lt;/p&gt;
&lt;p&gt;알고리즘은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;그래프 전체를 순서대로 순회한다. 이 때 칸이 &lt;code&gt;isVisited&lt;/code&gt;가 &lt;code&gt;false&lt;/code&gt;인 칸에서 bfs를 수행한다. 따라서 &lt;code&gt;isVisited&lt;/code&gt;는 전역 변수(혹은 call by reference)가 되어야 한다.&lt;/li&gt;
&lt;li&gt;bfs로 탐색한 칸은 서로 연합이 가능한 칸이다. bfs 탐색의 조건은 문제에 상세히 적혀있다. 그래프 전체를 순회하며 bfs 탐색을 실시하고 각 칸의 값을 조정하면, 이게 문제에서 말하는 &amp;lsquo;하루&amp;rsquo;가 지난 것이다. &lt;code&gt;isVisited&lt;/code&gt;가 &lt;code&gt;false&lt;/code&gt;인 칸만 연합을 수행하므로, 앞선 칸에서 수행한 bfs 탐색이 뒤에 있는 칸에 영향을 끼칠 일은 없다.&lt;/li&gt;
&lt;li&gt;1회의 인구 이동이 끝났어도 또 인구 이동이 가능할 수 있다. 따라서 1.을 더 이상 인구이동이 불가능해 질 때까지 수행한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;queue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;ptr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;popped&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;popped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;moves&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;queue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;union&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;unionPop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;isEmpty&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;newNode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;differ&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;differ&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;differ&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;unionPop&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;dividedPop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unionPop&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;union&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dividedPop&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;nlr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nlr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;nlr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;nlr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;graph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]]()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isVisited&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;]](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;answer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isEnd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isEnd&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isEnd&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;]](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 14502. 연구소</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-14502-laboratory/</link><pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-14502-laboratory/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14502"&gt;https://www.acmicpc.net/problem/14502&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;dfs와 bfs가 합쳐진 문제이다. 벽을 꼭 3개를 세워야 하므로 dfs를 이용하여 벽을 세울 위치를 전체 탐색할 수 있다. 연구소의 크기가 최대 8 * 8 이므로 전체 탐색하는데 큰 문제가 발생하지 않는다.&lt;/p&gt;
&lt;p&gt;벽을 세웠으면 bfs를 이용하여 바이러스가 퍼졌을 때의 연구소의 모습을 그린다. 이 때 바이러스가 지나간 자리는 2로 마킹되고, 벽은 바이러스가 지나가지 못하므로 &lt;code&gt;isVisited&lt;/code&gt;와 같은 배열이 없어도 이미 지나간 곳임을 알 수 있다.&lt;/p&gt;
&lt;p&gt;알고리즘을 순서대로 나타내면 다음과 같다.&lt;/p&gt;</description></item><item><title>BOJ 6087. 레이저 통신</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-6087-laser-communication/</link><pubDate>Wed, 05 Jul 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-6087-laser-communication/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/6087"&gt;https://www.acmicpc.net/problem/6087&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;다익스트라 알고리즘을 사용하여 해결하는 문제이다. 각 인접한 노드가 연결되어있다고 생각하고, 전의 노드에서 현재 노드로 온 방향과 수직인 노드만 거리를 1로 설정해주면 된다.&lt;/p&gt;
&lt;p&gt;일반적인 다익스트라 알고리즘 문제에서는 연결된 노드간의 거리가 주어지는데, 이 문제에서는 연결된 노드의 거리를 0으로 할지, 1로 할지 선택해야한다. 하지만 다익스트라 알고리즘과 BFS의 관계를 잘 생각해보면, 어렵지 않게 풀 수 있다(개인적으로 BFS는 일종의 다익스트라 특이 케이스라고 생각한다.)&lt;/p&gt;
&lt;p&gt;알고리즘은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;그래프에서 인접한 칸끼리는 서로 연결된 노드라고 가정함 (노드간 거리는 기본적으로 0으로 생각)&lt;/li&gt;
&lt;li&gt;현재 있는 칸에서 내가 바라보고 있는 방향을 기준으로 수직인 노드는 거리가 1, 아닌 노드는 0으로 설정&lt;/li&gt;
&lt;li&gt;2.를 반복하면서 다익스트라 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/ps/2023/ps-boj-6087-laser-communication/image-002-optimized-image.webp"&gt;&lt;p&gt;&lt;code&gt;vertical&lt;/code&gt;은 가로 이동 &lt;code&gt;horizontal&lt;/code&gt;은 세로 이동 &lt;code&gt;neutral&lt;/code&gt;은 중립 방향인데, 시작 지점이나 아래에서 설명할 다른 &lt;code&gt;Direction&lt;/code&gt;이지만 같은 거리에 있는 노드가 가지는 방향이다. &lt;code&gt;none&lt;/code&gt;은 아직 탐색하지 않은 노드가 가지는 방향이다.&lt;/p&gt;</description></item><item><title>BOJ 1049. 기타줄</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-1049-guitar-strings/</link><pubDate>Fri, 16 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-1049-guitar-strings/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1049"&gt;https://www.acmicpc.net/problem/1049&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;6개 묶음 패키지의 가격과 낱개의 가격이 각각 여러 개가 주어졌을 때, 가장 적은 비용으로 n개 이상의 수를 채워야 하는 문제이다.&lt;/p&gt;
&lt;p&gt;문제의 알고리즘은 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;패키지의 가격과 낱개의 가격이 같이 들어오므로 현재 가장 싼 패키지와 낱개의 가격과, 입력으로 들어온 가격을 각각 비교해서 갱신한다.&lt;/li&gt;
&lt;li&gt;패키지만 샀을때, 낱개만 샀을때, 패키지와 낱개를 동시에 샀을때 세가지 경우를 비교해서 가장 비용이 낮은 값을 출력한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 문제에서 구매 수량에 제한을 두지 않았으므로, 굳이 배열을 만들고 정렬을 할 필요가 없다. 패키지든 낱개든 무조건 가장 싼 가격만 알고 있으면 된다.&lt;/p&gt;</description></item><item><title>BOJ 11000. 강의실 배정</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-11000-classroom-assignment/</link><pubDate>Fri, 16 Jun 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-11000-classroom-assignment/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/11000"&gt;https://www.acmicpc.net/problem/11000&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;정렬 후 그리디를 수행하는 전형적인 그리디 알고리즘 문제이다.&lt;/p&gt;
&lt;p&gt;강의가 시작하는 시간과 끝나는 시간이 주어져 있으므로 배열에 입력으로 주어진 시간들을 저장한 다음에 정렬해서, 강의가 가장 많은 시간의 강의 수를 출력하면 된다.&lt;/p&gt;
&lt;p&gt;알고리즘을 글로 표현하면 다음과 같다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;수업이 시작하는 시간과 끝나는 시간을 배열 &lt;code&gt;lecture&lt;/code&gt;에 저장한다. 이때 배열은 &lt;code&gt;[(Int, Bool)]&lt;/code&gt; 타입이며, &lt;code&gt;Int&lt;/code&gt;에는 시간, &lt;code&gt;Bool&lt;/code&gt;에는 강의가 시작하는 시간일 경우 &lt;code&gt;true&lt;/code&gt;, 끝나는 시간일 경우 &lt;code&gt;false&lt;/code&gt;를 저장한다.&lt;/li&gt;
&lt;li&gt;배열 &lt;code&gt;lecture&lt;/code&gt;를 정렬한다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lecture&lt;/code&gt;를 for 반복문으로 전체 순회한다. 튜플의 두 번째 원소가 &lt;code&gt;true&lt;/code&gt;인 경우 현재 진행 중인 강의 수를 저장하는 변수 &lt;code&gt;current&lt;/code&gt;의 값을 1 더한다. &lt;code&gt;false&lt;/code&gt;인 경우 강의가 끝난 것 이므로 변수 &lt;code&gt;current&lt;/code&gt;의 값을 1 뺀다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이때, 배열 lecture를 시간순으로만 정렬하게 되면 문제에서 다음과 같은 부분 때문에 문제가 생긴다.&lt;/p&gt;</description></item><item><title>Programmers. 하노이의 탑</title><link>https://kelly-chui.github.io/ps/2023/ps-programmers-tower-of-hanoi/</link><pubDate>Wed, 03 May 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-programmers-tower-of-hanoi/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://school.programmers.co.kr/learn/courses/30/lessons/12946"&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12946&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;이런 문제는 문제를 읽었을 때 어떻게 풀어야 할지 감이 잘 잡히지 않는다. 이러한 상황에서는 우선 문제를 시각화 해보자.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/ps/2023/ps-programmers-tower-of-hanoi/image-002-optimized-image.webp"&gt;&lt;p&gt;좌측은 n = 1일때, 우측은 n = 2일때의 이동을 시각화 한 것이다. 빨간색 숫자는 원판을 뜻하고 파란색 선은 이동루트를 뜻한다. n = 1 일 때는 당연한 이동 경로지만 n = 2일 때는 중간에 있는 기둥을 사용해야한다. 하지만 아직까진 규칙이 뚜렷하게 드러나지 않는다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/ps/2023/ps-programmers-tower-of-hanoi/image-003-optimized-image.webp"&gt;&lt;p&gt;n = 3 일때의 이동경로를 시각적으로 나타냈다. 사실 직접 손으로 그리지 않고 다른 사람이 그린 그림으로 봤을 땐 아직도 규칙이 아리송 할 수 있지만 손으로 직접 그렸을 땐 규칙을 바로 알아 챌 수 있다.&lt;/p&gt;</description></item><item><title>BOJ 1753. 최단경로</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-1753-shortest-path/</link><pubDate>Sun, 05 Mar 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-1753-shortest-path/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1753"&gt;https://www.acmicpc.net/problem/1753&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;다익스트라 입문 문제이다. 단, 스위프트로 풀려면 힙을 직접 구현해야 한다.&lt;/p&gt;
&lt;p&gt;입력으로 주어지는 엣지의 웨이트가 모두 같다는 조건이 없으므로, BFS가 아닌 다익스트라로 탐색해야 한다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Heap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;isEmpty&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;currentIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;currentIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;parentIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentIndex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;currentIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;parentIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swapAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parentIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parentIndex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;mutating&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;deleteMin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;min&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;removeLast&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;currentIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;leftChildIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;currentIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;rightChildIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;currentIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;leftChildIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;minChildIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;leftChildIndex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rightChildIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rightChildIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;leftChildIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;minChildIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rightChildIndex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;minChildIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;currentIndex&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;swapAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minChildIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;minChildIndex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;min&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;heap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Heap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;distanceTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;edge&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deleteMin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;distanceTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;distanceTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;distanceTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;heap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ve&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;graph&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)]](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ve&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ve&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;uvw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;uvw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;uvw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;uvw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;distanceTable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;repeating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300_001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ve&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dijkstra&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="n"&gt;ve&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;distanceTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;300_001&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;INF&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distanceTable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 14003. 가장 긴 증가하는 부분 수열 5</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-14003-longest-increasing-subsequence-5/</link><pubDate>Wed, 01 Mar 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-14003-longest-increasing-subsequence-5/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/14003"&gt;https://www.acmicpc.net/problem/14003&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;LIS(Longest Increasing Subsequence)라고 하는 유명한 DP 문제이다. 이 문제 외에도 연계된 문제들이 많으니 1번(BOJ 11053)부터 차례대로 풀면 어느새 여기까지 풀게 된다.&lt;/p&gt;
&lt;img loading="lazy" src="https://kelly-chui.github.io/ps/2023/ps-boj-14003-longest-increasing-subsequence-5/image-002-optimized-image.webp"&gt;&lt;p&gt;이 문제들은 총 2가지 기준으로 분류된다. 첫 번째 기준은 O(n²), O(nlogn) 두 번째는 LIS 출력 여부이다. 이 중에 O(nlogn) 알고리즘을 사용하고 LIS를 직접 출력해야 하는 문제가 이 문제이다. 원래는 Swift로 작성하려 했지만, 백준의 입력시간 문제 때문에 Swift론 입력 횟수가 적은 O(n²)문제를 풀고 O(nlogn) 문제는 C++로 작성하였다.&lt;/p&gt;
&lt;p&gt;기본적인 알고리즘 콘셉트는 다음과 같다.&lt;/p&gt;</description></item><item><title>BOJ 16398. 행성 연결</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-16398-planet-connection/</link><pubDate>Sat, 25 Feb 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-16398-planet-connection/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/16398"&gt;https://www.acmicpc.net/problem/16398&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;모든 행성을 연결해야 하고, 그 비용을 최소로 하려면 최소 스패닝 트리(MST)를 찾아야 한다.&lt;/p&gt;
&lt;p&gt;따라서 알고리즘의 흐름은 다음과 같아진다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;2차원 배열로 입력받은 플로우 관리비용을 정렬한다.&lt;/li&gt;
&lt;li&gt;Kruskal 알고리즘을 이용해 최소 스패닝 트리를 구한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여기서 에지(플로우 관리비용)의 정보가 2차원 배열로 입력되므로 배열을 순회하여 (노드, 노드, 비용)꼴의 튜플 배열로 만들어 정렬했다.&lt;/p&gt;
&lt;p&gt;2차원 배열의 각 인덱스가 노드를 특정하므로 이렇게 하는 것이 최선이라 생각했다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;pa&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;pb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;pa&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="nc"&gt;Foundation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="kc"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;edges&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="bp"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="bp"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 4195. 친구 네트워크</title><link>https://kelly-chui.github.io/ps/2023/ps-boj-4195-friend-network/</link><pubDate>Thu, 23 Feb 2023 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2023/ps-boj-4195-friend-network/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/4195"&gt;https://www.acmicpc.net/problem/4195&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;전형적인 Union-Find 문제이지만, 각 원소들이 정수가 아닌 문자열로 구성되어 있는 특징이 있다. 정수를 문자열로 대응시키는 것은 Dictionary를 쓰면 쉽게 할 수 있으므로 다음과 같은 방식으로 알고리즘이 진행된다&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;입력값(문자열 2개)에 대해 각 문자열이 Dictionary에 대응되는 Value가 있는지 판단한다.&lt;/li&gt;
&lt;li&gt;1에서 없다면 Dictionary에 &lt;code&gt;[String:Integer]&lt;/code&gt; 꼴로 매핑한다. 있다면 그냥 넘어간다.&lt;/li&gt;
&lt;li&gt;매핑이 끝났다면, 들어온 두 문자열로 &lt;code&gt;union(a, b)&lt;/code&gt; 연산을 하고 그 집합 내부의 원소의 개수를 카운트한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여기서 문제는 3번이다. 어떻게 해야 효율적으로 집합 내부의 원소를 카운트 할 수 있을까?&lt;/p&gt;</description></item><item><title>BOJ 1726. 로봇</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-1726-robot/</link><pubDate>Fri, 18 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-1726-robot/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1726"&gt;https://www.acmicpc.net/problem/1726&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;로봇이 바라보는 방향에 따라서 갈 수 있는 노드가 달라진다 -&amp;gt; 3차원 그래프다 (세로 m, 가로 n, 높이가 4인)&lt;/p&gt;
&lt;p&gt;이 발상만 빠르게 해낸다면 평범한 BFS 문제가 된다.&lt;/p&gt;
&lt;p&gt;하나의 노드에서 최대 5개의 노드와 연결이 가능하다(회전 2방향, 전진 3방향) 하지만 2칸 이상 전진했을때, 앞선 칸이 1이면 넘어가지 못한다. (점프를 할 수 없다)&lt;/p&gt;
&lt;p&gt;이것만 주의하고 BFS 탐색을 하면 쉽게 결과를 낼 수 있다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# east 0 west 1 south 2 north 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;dir&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rotate&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;currentDir&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;currentDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;currentDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;currentDir&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentDir&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;currentDir&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;currentDir&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;currentDir&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentCount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentDir&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rotate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;isVisited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 3055. 탈출</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-3055-escape/</link><pubDate>Thu, 17 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-3055-escape/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/3055"&gt;https://www.acmicpc.net/problem/3055&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;입력으로 그래프가 주어지고, 어느 칸에서 BFS를 시작해야하는지 알려준다. 문제를 읽어보면 고슴도치와 물 둘 다 BFS 탐색을 해야 하는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;주의할 점은 예제에는 초기에 물인 칸이 1개밖에 없지만 문제를 읽어보면 1칸이라는 제약조건이 없다. 따라서 물이 여러칸일 때도 생각하고 프로그래밍을 해야 한다.&lt;/p&gt;
&lt;p&gt;처음에 두 가지 생각을 했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;BFS탐색을 각각 따로 하는 방법&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;고슴도치를 먼저 BFS 탐색시켜서 그래프에 각 칸마다 몇번째 이동에 도달하는지 검사한다.&lt;/li&gt;
&lt;li&gt;다음에 물을 BFS 탐색해서 1의 결과가 가능한지를 판단한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;고슴도치와 물을 단계별로 번갈아가면서 BFS 탐색 하는 방법&lt;/p&gt;</description></item><item><title>BOJ 7576. 토마토</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-7576-tomato/</link><pubDate>Thu, 10 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-7576-tomato/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/7576"&gt;https://www.acmicpc.net/problem/7576&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;처음엔 무난한 BFS 문제라고 생각했다. 처음부터 익어있는 토마토(루트 토마토라고 하겠다.)가 들어있는 칸을 알아낸 다음에 반복문으로 BFS를 적용하고, 루트 토마토를 할 때마다 만약 칸에 더 적은 숫자가 들어 갈 수 있다면 숫자를 업데이트 하는 식으로 문제를 풀었다.&lt;/p&gt;
&lt;p&gt;그랬더니 시간초과가 나온다. 쓸데없는 연산이 너무 많아서 그렇다.&lt;/p&gt;
&lt;p&gt;정확한 풀이는 BFS 큐를 처음 만들때부터 모든 루트 토마토를 넣어서 초기화 하는 것이었다. 그러면 모든 루트 토마토를 기준으로 동시에 탐색할 수 있으니까.&lt;/p&gt;
&lt;p&gt;칸을 탐색할때도 더 높은 숫자가 나오면 그 칸은 큐에 넣을 필요가 없다. 이미 전에 했던 탐색이 더 좋은 결과를 가져다 주었을태니&lt;/p&gt;</description></item><item><title>BOJ 1697. 숨바꼭질</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-1697-hide-and-seek/</link><pubDate>Mon, 07 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-1697-hide-and-seek/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1697"&gt;https://www.acmicpc.net/problem/1697&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;입력으로 수빈이와 동생의 위치, 그리고 수빈이가 이동할 수 있는 제약조건을 알려준다.&lt;/p&gt;
&lt;p&gt;수빈이의 위치보다 동생의 위치가 더 앞에 있거나 같을때는 (n &amp;gt;= k) 뒤로 가는 방법이 한칸 이동하는 것 밖에 없으므로 n - k 로 쉽게 결과를 도출 할 수 있다.&lt;/p&gt;
&lt;p&gt;그 외의 경우에는 각각의 좌표를 노드라고 생각했을 때, 이 그래프는 각 노드가 노드값이 1만큼 크거나 작은 노드와 2배인 노드와 연결되어 있다.&lt;/p&gt;
&lt;p&gt;따라서 BFS를 이용하면 쉽게 해결 할 수 있다.&lt;/p&gt;</description></item><item><title>BOJ 2331. 반복 수열</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-2331-repeating-sequence/</link><pubDate>Mon, 07 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-2331-repeating-sequence/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2331"&gt;https://www.acmicpc.net/problem/2331&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;수열을 만드는 반복문을 만든다.&lt;/li&gt;
&lt;li&gt;도중에 기존에 있는 원소와 같은 원소가 나오면 반복문을 종료한다.&lt;/li&gt;
&lt;li&gt;처음으로 나온 같은 원소의 인덱스를 출력한다. (인덱스는 0부터 시작이기에 더하고 뺄 필요가 없다.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;너무 간단하게 풀렸는데 시간복잡도가 별로 좋아보이진 않는다. 더 좋은 방법이 있을듯 싶다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 2667. 단지 번호 붙이기</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-2667-complex-numbering/</link><pubDate>Mon, 07 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-2667-complex-numbering/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2667"&gt;https://www.acmicpc.net/problem/2667&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;그래프가 입력으로 주어지고, 각 노드마다 탐색의 범위가 상하좌우로 제한된다. 앞서 해결했던 미로 탐색과 순열 사이클을 섞어놓은 듯 한 문제이다.&lt;/p&gt;
&lt;p&gt;따라서 다음과 같은 과정으로 출력값을 얻었다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;전체 그래프를 탐색하는 2중 반복문을 작성한다.&lt;/li&gt;
&lt;li&gt;방문하지 않은 노드가 나올 때마다 그래프 탐색(DFS, BFS)를 실시한다.&lt;/li&gt;
&lt;li&gt;각 그래프를 탐색했을때 노드의 개수를 저장하고 정렬한 다음에 출력한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;isVisited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 10451. 순열 사이클</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-10451-permutation-cycle/</link><pubDate>Sun, 06 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-10451-permutation-cycle/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/10451"&gt;https://www.acmicpc.net/problem/10451&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;순열이 각각의 (1부터 시작하는)인덱스와 매칭되어있는 그래프를 만들면 쉽게 해결된다. (친절하게 문제에 그림도 있다.)&lt;/p&gt;
&lt;p&gt;순열과 인덱스는 내부 원소들이 순서를 제외하고 같으므로 무조건 내부에 사이클을 형성하게 된다.&lt;/p&gt;
&lt;p&gt;따라서 문제에서 주어진 그대로 우리는 서로 가르키는 방향을 재귀로 따라가고, 이미 방문한 숫자가 나온다면 재귀를 종료시키기를 반복해서 생기는 사이클의 총 개수를 카운트 하기만 하면 된다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;permutation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;permutation&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;per&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n_temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;per_temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;per_temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;permutation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;isVisited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;굳이 재귀를 쓰지 않더라도 반복문만으로도 깔끔한 코드가 나올것 같다.&lt;/p&gt;</description></item><item><title>BOJ 1260. dfs와 bfs</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-1260-dfs-and-bfs/</link><pubDate>Sun, 06 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-1260-dfs-and-bfs/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/1260"&gt;https://www.acmicpc.net/problem/1260&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;심플하다. 입력값으로 그래프가 주어지고, DFS와 BFS를 이용해 탐색한 결과를 각각 출력하면 된다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dfsArray&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisitedDFS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfsArray&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;])):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;isVisitedDFS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dfsArray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bfsArray&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;QueueBFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisitedBFS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;QueueBFS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;QueueBFS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;QueueBFS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsArray&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;])):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;isVisitedBFS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;QueueBFS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isVisitedBFS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;isVisitedDFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;isVisitedBFS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dfsArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;bfsArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dfsArray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bfsArray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;dfsArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;bfsArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>BOJ 2178. 미로 탐색</title><link>https://kelly-chui.github.io/ps/2022/ps-boj-2178-maze-search/</link><pubDate>Sun, 06 Nov 2022 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/ps/2022/ps-boj-2178-maze-search/</guid><description>&lt;h2 id="문제"&gt;문제&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.acmicpc.net/problem/2178"&gt;https://www.acmicpc.net/problem/2178&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="풀이"&gt;풀이&lt;/h2&gt;
&lt;p&gt;입력값으로 미로의 크기와 구성이 주어진다.&lt;/p&gt;
&lt;p&gt;미로 안에서는 값이 1인 칸으로만 이동 할 수 있고, 또 각 칸에서는 상하좌우의 칸으로밖에 이동하지 못한다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 현재 칸에서 상하좌우의 칸을 탐색해서 1인 경우에만 Queue에 넣는다.&lt;/p&gt;
&lt;p&gt;이 문제에서는 각 노드를 방문했는지의 여부보다 몇번째에 방문했는지의 여부가 더 중요하다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 이전 노드의 방문 순서에 1을 더한 값을 현재 노드의 방문 순서로 한다. (isVisited가 Bool이 아닌 Integer로 구현된다)&lt;/p&gt;
&lt;p&gt;이렇게 얻어낸 두가지 인사이트로 BFS를 구현한다.&lt;/p&gt;
&lt;h3 id="코드"&gt;코드&lt;/h3&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;visit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;down&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;maze&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;bfsQ&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;maze&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;maze&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bfs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;시작 노드와 종료 노드가 명확하게 정해져 있으므로 DFS로도 풀릴것이라는 생각이 든다.&lt;/p&gt;</description></item><item><title>About</title><link>https://kelly-chui.github.io/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/about/</guid><description>&lt;p&gt;Personal development blog.&lt;/p&gt;</description></item></channel></rss>