NHN NEXT 게임 서버 프로그래밍 강의 자료입니다. 최소한의 필요한 이론 내용은 질문 위주로 구성되어 있고 (답은 학생들 개별로 고민해와서 피드백 받는 방식) 해당 내용에 맞는 실습(구현) 과제가 포함되어 있습니다.
참고로, 서버 아키텍처에 관한 과목은 따로 있어서 본 강의에는 포함되어 있지 않습니다.
책 읽어주는 딥러닝: 배우 유인나가 해리포터를 읽어준다면 DEVIEW 2017Taehoon Kim
발표 영상 : https://youtu.be/klnfWhPGPRs
코드 : https://github.com/carpedm20/multi-speaker-tacotron-tensorflow
음성 합성 데모 : http://carpedm20.github.io/tacotron
발표 소개 : https://deview.kr/2017/schedule/182
딥러닝을 활용한 음성 합성 기술을 소개하고 개발 경험과 그 과정에서 얻었던 팁을 공유하고자 합니다.
NDC Python 게임서버 안녕하십니까? : 몬스터 슈퍼리그 게임 서버 편의 후속으로 기획된 발표입니다. 사내 준비 도중 "너굴" 님의 질문에서 시작되었습니다.
이 발표는 잘 알려진 RPC Framework 인 Thrift, gRPC를 살펴보고 예시로 오델로 게임을 만들어보면서 기존 RPC framework 들이 게임의 서버/클라 구조에 잘 어울리지는 살펴보고 왜 몬스터 슈퍼리그에서 그런 선택을 했는지 살펴봅니다.
그리고 게임에 맞게 RPC 를 설계하고 이를 이용하여 온라인 오델로 게임을 완성해봅니다.
딥러닝과 강화 학습으로 나보다 잘하는 쿠키런 AI 구현하기 DEVIEW 2016Taehoon Kim
발표 영상 : https://goo.gl/jrKrvf
데모 영상 : https://youtu.be/exXD6wJLJ6s
Deep Q-Network, Double Q-learning, Dueling Network 등의 기술을 소개하며, hyperparameter, debugging, ensemble 등의 엔지니어링으로 성능을 끌어 올린 과정을 공유합니다.
[GomGuard] 뉴런부터 YOLO 까지 - 딥러닝 전반에 대한 이야기JungHyun Hong
뉴런, perceptron, cnn, r-cnn, fast r-cnn, faster r-cnn 및
backpropagation, activation function, batch normalization, cost function, optimizer 등 전반적인 딥뉴럴 네트워크에 대한 지식을 다루고 있습니다.
mail : knholic@gmail.com
blog : gomguard.tistory.com
NHN NEXT 게임 서버 프로그래밍 강의 자료입니다. 최소한의 필요한 이론 내용은 질문 위주로 구성되어 있고 (답은 학생들 개별로 고민해와서 피드백 받는 방식) 해당 내용에 맞는 실습(구현) 과제가 포함되어 있습니다.
참고로, 서버 아키텍처에 관한 과목은 따로 있어서 본 강의에는 포함되어 있지 않습니다.
책 읽어주는 딥러닝: 배우 유인나가 해리포터를 읽어준다면 DEVIEW 2017Taehoon Kim
발표 영상 : https://youtu.be/klnfWhPGPRs
코드 : https://github.com/carpedm20/multi-speaker-tacotron-tensorflow
음성 합성 데모 : http://carpedm20.github.io/tacotron
발표 소개 : https://deview.kr/2017/schedule/182
딥러닝을 활용한 음성 합성 기술을 소개하고 개발 경험과 그 과정에서 얻었던 팁을 공유하고자 합니다.
NDC Python 게임서버 안녕하십니까? : 몬스터 슈퍼리그 게임 서버 편의 후속으로 기획된 발표입니다. 사내 준비 도중 "너굴" 님의 질문에서 시작되었습니다.
이 발표는 잘 알려진 RPC Framework 인 Thrift, gRPC를 살펴보고 예시로 오델로 게임을 만들어보면서 기존 RPC framework 들이 게임의 서버/클라 구조에 잘 어울리지는 살펴보고 왜 몬스터 슈퍼리그에서 그런 선택을 했는지 살펴봅니다.
그리고 게임에 맞게 RPC 를 설계하고 이를 이용하여 온라인 오델로 게임을 완성해봅니다.
딥러닝과 강화 학습으로 나보다 잘하는 쿠키런 AI 구현하기 DEVIEW 2016Taehoon Kim
발표 영상 : https://goo.gl/jrKrvf
데모 영상 : https://youtu.be/exXD6wJLJ6s
Deep Q-Network, Double Q-learning, Dueling Network 등의 기술을 소개하며, hyperparameter, debugging, ensemble 등의 엔지니어링으로 성능을 끌어 올린 과정을 공유합니다.
[GomGuard] 뉴런부터 YOLO 까지 - 딥러닝 전반에 대한 이야기JungHyun Hong
뉴런, perceptron, cnn, r-cnn, fast r-cnn, faster r-cnn 및
backpropagation, activation function, batch normalization, cost function, optimizer 등 전반적인 딥뉴럴 네트워크에 대한 지식을 다루고 있습니다.
mail : knholic@gmail.com
blog : gomguard.tistory.com
"R을 이용한 데이터 처리 & 분석 실무 - 서민구 지음" 정리 자료 #1
- https://thebook.io/006723/
- 첫번째 : goo.gl/FJjOlq
- 두번째 : goo.gl/Wdb90g
- 세번째 : goo.gl/80VGcn
- 네번째 : goo.gl/lblUsR
3. 환영합니다!
Sogang ICPC Team 2
저는...
✓ 박수현 – @shiftpsh / shiftpsh.com
✓ Sogang ICPC Team 전임 학회장 – 2019년
✓ ICPC 2019 Seoul Regional에 팀 Redshift로 참가 – 8위
✓ solved.ac를 만든 사람!
4. “고급” 스터디를 시작하기 전에...
Sogang ICPC Team 3
“고급” 스터디는 초급이나 중급 스터디와는 진행방식이 좀 다릅니다
✓ 옆 동네에서 하는 팀 빌딩이나 모의고사 등 재밌는 것들 → 없어요
✓ 기본적으로 혼자 열심히 하셔야 해요
– 여기 오실 정도의 여러분들이 PS에 미친 분들이라는 건 확실해 보이니 걱정하지
않겠습니다
5. “고급” 스터디를 시작하기 전에...
Sogang ICPC Team 4
다루게 되는 것들
✓ solved.ac 기준으로 에서 사이의 문제들
✓ 실무에서는 전혀 쓸 것 같지 않고 실제로도 별로 안 쓰이는 생소한 알고리즘과
자료구조들
– 하지만 대회에서는 나온다
✓ 여하튼 ICPC 등의 “대회 준비”에 초점이 맞춰져 있습니다
6. “고급” 스터디를 시작하기 전에...
Sogang ICPC Team 5
“고급”에 붙어 있는 따옴표는 뭐에요?
✓ 고급 스터디에서 다루는 자료구조와 알고리즘들은 대회 준비의 필요조건이지
충분조건이 아닙니다
– 이런 거 많이 아는 것보다 이미 아는 알고리즘을 잘 써먹는 방법을 공부하는 게
대회 성적에 훨씬 도움이 됩니다
✓ 진짜 “고급” – 이미 알고 있는 알고리즘들을 잘 써먹는 능력을 기르는 스터디
– 팀 연습 등
7. “고급” 스터디를 시작하기 전에...
Sogang ICPC Team 6
그럼 이거 왜 하는 거에요?
✓ 모르면 아예 못 푸는 내용들을 대비하기 위해
✓ 남들한테는 다 웰노운인데 나한테만 아닌 것들을 나에게도 웰노운으로 만들어 써먹기
위해
– 팀노트에 적어가세요
✓ solved.ac 경험치 올리기 위해
8. Remarks on Segment Trees
Sogang ICPC Team 7
1–10
1–5 6–10
1–3 4–5 6–8 9–10
1–2 3 4 5 6–7 8 9 10
1 2 6 7
f (x, s, e, · · · ) = f
(
2x, s,
⌊
s + e
2
⌋
, · · ·
)
+ f
(
2x + 1,
⌊
s + e
2
⌋
+ 1, e, · · ·
)
9. Remarks on Segment Trees
Sogang ICPC Team 8
1–10
1–5 6–10
1–3 4–5 6–8 9–10
1–2 3 4 5 6–7 8 9 10
1 2 6 7
A5 · · · A9 의 합?
10. Remarks on Segment Trees
Sogang ICPC Team 9
✓ Al · · · Ar 의 합 쿼리 = O (log n)
✓ Ai 업데이트 = O (log n)
11. Lazy Propagation
Sogang ICPC Team 10
✓ Al · · · Ar 의 합 쿼리
✓ Al · · · Ar 업데이트
의 두 쿼리를 처리해야 한다고 생각해 보자
– 하나하나 업데이트한다면 쿼리 한 번에 O ((r − l) log n) → 사실상 O (n log n)
12. Lazy Propagation
Sogang ICPC Team 11
쿼리 한 번에 O (n log n)은 느려도 너무 느리다
→ 업데이트할 때 매번 리프 노드까지 보내지 말자
→ 트리를 하나 더 만들어서 거기다 업데이트하고 쿼리할 때 한꺼번에 업데이트하자
13. Lazy Propagation
Sogang ICPC Team 12
40 ll a[1000001], tree[1048576 * 2], lazy[1048576 * 2];
41
42 void _propagate(int x, int s, int e) {
43 if (!lazy[x]) return;
44 tree[x] += (e - s + 1) * lazy[x];
45 if (s != e) {
46 lazy[x * 2] += lazy[x];
47 lazy[x * 2 + 1] += lazy[x];
48 }
49 lazy[x] = 0;
50 }
lazy라는 이름으로 별도의 트리를 만든다
14. Lazy Propagation
Sogang ICPC Team 13
40 ll a[1000001], tree[1048576 * 2], lazy[1048576 * 2];
41
42 void _propagate(int x, int s, int e) {
43 if (!lazy[x]) return;
44 tree[x] += (e - s + 1) * lazy[x];
45 if (s != e) {
46 lazy[x * 2] += lazy[x];
47 lazy[x * 2 + 1] += lazy[x];
48 }
49 lazy[x] = 0;
50 }
노드 x에 아직 업데이트하지 않은 값이 있다면 트리에 업데이트해주는 메서드
15. Lazy Propagation
Sogang ICPC Team 14
52 ll _sum(int x, int s, int e, int l, int r) {
53 _propagate(x, s, e);
54 if (l > e || r < s) return 0;
55 if (l <= s && e <= r) return tree[x];
56 int m = (s + e) / 2;
57 return _sum(x * 2 , s, m, l, r) +
58 _sum(x * 2 + 1, m + 1, e, l, r);
59 }
합 쿼리를 계산할 때 propagation을 해 줘야 한다
16. Lazy Propagation
Sogang ICPC Team 15
61 void _update(int x, int s, int e, int l, int r, ll dv) {
62 _propagate(x, s, e);
63 if (l > e || r < s) return;
64 if (l <= s && e <= r) {
65 tree[x] += (e - s + 1) * dv;
66 if (s != e) {
67 lazy[x * 2] += dv;
68 lazy[x * 2 + 1] += dv;
69 }
70 return;
71 }
72 int m = (s + e) / 2;
73 _update(x * 2 , s, m, l, r, dv);
74 _update(x * 2 + 1, m + 1, e, l, r, dv);
75 tree[x] = tree[x * 2] + tree[x * 2 + 1];
76 }
업데이트할 때도 propagation을 해 줘야 한다
17. Lazy Propagation
Sogang ICPC Team 16
61 void _update(int x, int s, int e, int l, int r, ll dv) {
62 _propagate(x, s, e);
63 if (l > e || r < s) return;
64 if (l <= s && e <= r) {
65 tree[x] += (e - s + 1) * dv;
66 if (s != e) {
67 lazy[x * 2] += dv;
68 lazy[x * 2 + 1] += dv;
69 }
70 return;
71 }
72 int m = (s + e) / 2;
73 _update(x * 2 , s, m, l, r, dv);
74 _update(x * 2 + 1, m + 1, e, l, r, dv);
75 tree[x] = tree[x * 2] + tree[x * 2 + 1];
76 }
현재 확인하는 구간이 업데이트 구간 안에 있다면 리프 노드까지 가지 않고 lazy를
업데이트하고 끝낸다
19. 구간 합 구하기 2 #
10999
Sogang ICPC Team 18
✓ n ≤ 106
✓ m + k ≤ 20000
구현해보자
20. 구간 합 구하기 2 #
10999
Sogang ICPC Team 19
115 while (q--) {
116 int op, l, r;
117 cin >> op >> l >> r;
118 if (op == 1) {
119 ll dv;
120 cin >> dv;
121 update(l, r, dv);
122 } else { // op == 2
123 cout << sum(l, r) << 'n';
124 }
125 }
source code
21. JuQueen #
10277
Sogang ICPC Team 20
코어가 4, 587, 520개인 컴퓨터의 클럭을 변경하는 프로그램을 짜야 한다. N 단계의 클럭이
가능하고
✓ CPU x의 클럭을 s단계만큼 증감
✓ CPU a · · · b의 클럭을 s단계만큼 증감
✓ CPU x의 클럭 단계 출력
중 하나를 할 수 있다.
클럭은 한 단계씩만 올라가거나 내려가며, 여러 코어에 대해 여러 단계를 한꺼번에 증감할
경우 그 중 하나라도 0단계나 N 단계에 도달하면 증감을 종료하고 증감한 만큼의 단계를
출력한다.
22. JuQueen #
10277
Sogang ICPC Team 21
클럭은 한 단계씩만 올라가거나 내려가며, 여러 코어에 대해 여러 단계를 한꺼번에 증감할
경우 그 중 하나라도 0단계나 N 단계에 도달하면 증감을 종료하고 증감한 만큼의 단계를
출력한다.
✓ 지금 클럭들이 1, 2, 3, 4고 N = 6이라면, 클럭 4단계를 올리라는 명령을 내린다면 2
단계만 올라가고 끝난다
23. JuQueen #
10277
Sogang ICPC Team 22
CPU a · · · b의 클럭 단계의 최솟값을 mn, 최댓값을 mx라 하고, s만큼 증감하고자 한다면
✓ mx + s > N 이라면? N − mx만큼만 올릴 수 있다
✓ mn + s < 0이라면? mn만큼만 내릴 수 있다
✓ 둘 다 아니라면 s만큼 올릴 수 있다
24. JuQueen #
10277
Sogang ICPC Team 23
세 가지 연산을 할 수 있는 자료구조가 필요
✓ 인덱스 l · · · r에서의 최솟값 구하기
✓ 인덱스 l · · · r에서의 최댓값 구하기
✓ 인덱스 l · · · r을 전부 s만큼 증가시키기
하나의 원소 i에 대해서만 연산할 경우 l = r = i
25. JuQueen #
10277
Sogang ICPC Team 24
A = {a0, a1, · · · , an}
A′
= {a0 + d, a1 + d, · · · , an + d}
이라고 하면
max
a′∈A′
(
a′
)
= max
a∈A
(a) + d
min
a′∈A′
(
a′
)
= min
a∈A
(a) + d
이 성립 → 그냥 더해주면 된다. 별 문제 없다
26. JuQueen #
10277
Sogang ICPC Team 25
✓ 인덱스 l · · · r에서의 최솟값 구하기
✓ 인덱스 l · · · r에서의 최댓값 구하기
· · · 를 하기 위해 세그먼트 트리를 튜플 ⟨min, max⟩ 로 만들고
✓ 인덱스 l · · · r을 전부 s만큼 증가시키기
· · · 를 하기 위해 lazy propagate 하면 되겠다!
27. JuQueen #
10277
Sogang ICPC Team 26
40 struct mii {
41 ll mn, mx;
42 };
43
44 mii tree[8388608 * 2];
45 int lazy[8388608 * 2];
46
47 int inf = 987654321;
48 int c, n, o;
source code
first, second는 헷갈리니까 struct를 새로 만든다. 어차피 정렬할 것도 아닌데· · ·
28. JuQueen #
10277
Sogang ICPC Team 27
50 void _propagate(int x, int s, int e) {
51 if (!lazy[x]) return;
52 tree[x].mn += lazy[x];
53 tree[x].mx += lazy[x];
54 if (s != e) {
55 lazy[x * 2] += lazy[x];
56 lazy[x * 2 + 1] += lazy[x];
57 }
58 lazy[x] = 0;
59 }
source code
Propagation – 더해주는 쿼리를 처리해 주기 위함
29. JuQueen #
10277
Sogang ICPC Team 28
61 ll _minimum(int x, int s, int e, int l, int r) {
62 _propagate(x, s, e);
63 if (l > e || r < s) return inf;
64 if (l <= s && e <= r) return tree[x].mn;
65 int m = (s + e) / 2;
66 return min(_minimum(x * 2, s, m, l, r),
67 _minimum(x * 2 + 1, m + 1, e, l, r));
68 }
source code
구간 최솟값 쿼리를 처리하면서 propagation도 같이 한다
30. JuQueen #
10277
Sogang ICPC Team 29
70 ll _maximum(int x, int s, int e, int l, int r) {
71 _propagate(x, s, e);
72 if (l > e || r < s) return 0;
73 if (l <= s && e <= r) return tree[x].mx;
74 int m = (s + e) / 2;
75 return max(_maximum(x * 2, s, m, l, r),
76 _maximum(x * 2 + 1, m + 1, e, l, r));
77 }
source code
최댓값에 대해서도 동일하게 처리해 준다
31. JuQueen #
10277
Sogang ICPC Team 30
79 void _update(int x, int s, int e, int l, int r, ll dv) {
80 _propagate(x, s, e);
81 if (l > e || r < s) return;
82 if (l <= s && e <= r) {
83 tree[x].mn += dv;
84 tree[x].mx += dv;
85 if (s != e) {
86 lazy[x * 2] += dv;
87 lazy[x * 2 + 1] += dv;
88 }
89 return;
90 }
91 int m = (s + e) / 2;
92 _update(x * 2 , s, m, l, r, dv);
93 _update(x * 2 + 1, m + 1, e, l, r, dv);
94 tree[x].mn = min(tree[x * 2].mn, tree[x * 2 + 1].mn);
95 tree[x].mx = max(tree[x * 2].mx, tree[x * 2 + 1].mx);
96 }
source code
32. JuQueen #
10277
Sogang ICPC Team 31
98 ll minimum(int l, int r) {
99 return _minimum(1, 0, c - 1, l, r);
100 }
101
102 ll maximum(int l, int r) {
103 return _maximum(1, 0, c - 1, l, r);
104 }
105
106 void update(int l, int r, ll dv) {
107 _update(1, 0, c - 1, l, r, dv);
108 }
source code
함수 인자가 너무 많으면 헷갈리므로 개인적으로는 첫 호출을 하는 함수를 따로 만들어서
사용하는 중
33. JuQueen #
10277
Sogang ICPC Team 32
118 string op;
119 cin >> op;
120 if (op[0] == 's') { // ”state”
121 int x;
122 cin >> x;
123 cout << minimum(x, x) << 'n';
124 } else if (op[0] == 'g') { // ”groupchange”
source code
값을 구하는 쿼리는 따로 만들 필요 없이 최솟값이나 최댓값 쿼리로 해결 가능하다
34. JuQueen #
10277
Sogang ICPC Team 33
124 } else if (op[0] == 'g') { // ”groupchange”
125 int a, b, s;
126 cin >> a >> b >> s;
127
128 ll mn = minimum(a, b), mx = maximum(a, b);
129 if (s > 0 && s + mx > n) {
130 update(a, b, n - mx);
131 cout << n - mx << 'n';
132 } else if (s < 0 && s + mn < 0) {
133 update(a, b, -mn);
134 cout << -mn << 'n';
135 } else {
136 update(a, b, s);
137 cout << s << 'n';
138 }
139 } else { // ”change”
source code
구간 최대/최소를 구해서 증감할 수 있는 만큼 증감해 주고 결과를 출력한다
35. JuQueen #
10277
Sogang ICPC Team 34
139 } else { // ”change”
140 int x, s;
141 cin >> x >> s;
142
143 ll val = minimum(x, x);
144 if (s > 0 && s + val > n) {
145 update(x, x, n - val);
146 cout << n - val << 'n';
147 } else if (s < 0 && s + val < 0) {
148 update(x, x, -val);
149 cout << -val << 'n';
150 } else {
151 update(x, x, s);
152 cout << s << 'n';
153 }
154 }
155 }
source code
마찬가지.
36. Lazy Propagation Not on Segment Trees
Sogang ICPC Team 35
Lazy propagation의 아이디어는 세그먼트 트리에 한정해서 쓰이지 않는다
37. Pixel Triangles #
16572
Sogang ICPC Team 36
2, 000 × 2, 000 크기의 격자 판이 주어지며, 각 픽셀(칸)은 행과 열을 이용해서 위치가
표시된다. 가장 왼쪽 열이 1열, 가장 위쪽 행이 1행이다.
이 때 픽셀 삼각형의 정의는 다음과 같다.
✓ 픽셀 삼각형은 3개의 자연수 A, B, C 에 대해서 P (A, B, C)로 표현된다.
✓ P (A, B, C) = {(x, y) | A ≤ x, B ≤ y, 0 ≤ (x − A) + (y − B) ≤ C − 1}
격자 위의 픽셀들로 구성된 픽셀 삼각형이 n ≤ 4, 000, 000개 주어졌을 때, 픽셀 삼각형들이
덮는 픽셀의 개수를 출력해라.