1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
# Misskey 리버시 봇 개발
Misskey의 리버시 기능을 지원하는 봇의 개발 방법을 소개합니다.
1. `games/reversi` 스트림에 다음 매개변수를 붙여 접속합니다:
* `i`: 봇 계정의 API 키
2. 대국 초대가 오면 스트림에서 `invited` 이벤트가 발생합니다
* 이벤트 내용에 `parent`라는 이름으로 대국 신청을 한 유저의 정보가 포함되어 있습니다
3. `games/reversi/match`에 `user_id`로 `parent`의 `id`가 포함된 요청을 전송합니다
4. 문제가 없으면 게임 정보가 반환되므로, `games/reversi-game` 스트림에 아래의 매개변수를 붙여 접속합니다:
* `i`: 봇 계정의 API 키
* `game`: `game`의 `id`
5. 상대방이 게임의 설정을 변경할 때 마다 `update-settings` 이벤트가 발생하므로, 필요에 따라 별도의 처리 과정을 진행할 수 있습니다
6. 설정에 동의하면 `{ type: 'accept' }` 메시지를 스트림으로 전달합니다
7. 게임이 시작되면 `started` 이벤트가 발생합니다
* 이벤트 내용에는 게임 정보가 포함됩니다
8. 돌을 치려면, 스트림에 `{ type: 'set', pos: <위치> }`를 전달합니다(위치 계산 방법은 후술)
9. 상대방 또는 자신이 돌을 치면 스트림에서 `set` 이벤트가 발생합니다
* `color` 에는 돌의 색상이 포함되어 있음
* `pos` 에는 위치 정보가 포함되어 있음
## 위치 계산 방법
8x8 크기의 맵을 생각할 경우, 각 칸의 위치(인덱스라고 부릅니다)는 다음과 같습니다:
```
+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7|
+--+--+--+--+--+--+--+--+
| 8| 9|10|11|12|13|14|15|
+--+--+--+--+--+--+--+--+
|16|17|18|19|20|21|22|23|
...
```
### X,Y 좌표를 인덱스로 변환
```
pos = x + (y * mapWidth)
```
`mapWidth`는 게임 정보의 `map`에서 다음과 같이 계산할 수 있습니다:
```
mapWidth = map[0].length
```
### 인덱스에서 X,Y 좌표로 변환
```
x = pos % mapWidth
y = Math.floor(pos / mapWidth)
```
## 맵 정보
맵 정보는 게임 정보의 `map`에 들어있습니다. 문자열이 배열되어 있어서 각 글자가 칸 정보를 나타냅니다. 이것을 바탕으로 맵의 디자인을 알 수 있습니다:
* `(공간)` ... 칸 없음
* `-` ... 칸
* `b` ... 처음 배치되는 흑돌
* `w` ... 처음 배치되는 백돌
예를 들어, 4*4 와 같은 단순한 맵이 있다고 가정합니다:
```text
+---+---+---+---+
| | | | |
+---+---+---+---+
| | ○ | ● | |
+---+---+---+---+
| | ● | ○ | |
+---+---+---+---+
| | | | |
+---+---+---+---+
```
이 경우, 맵 데이터는 아래와 같습니다:
```javascript
['----', '-wb-', '-bw-', '----']
```
## 사용자에게 폼을 제시하여 소통할 수 있는 봇 제작
사용자와 소통을 위해, 게임 설정 화면을 통해서 사용자에게 폼을 제시할 수 있습니다. 예를 들어, 봇의 난이도를 사용자가 설정할 수 있도록 하는 등의 구현이 가능합니다.
폼을 제시하려면, `reversi-game` 스트림으로 다음 메시지를 전송합니다:
```javascript
{
type: 'init-form',
body: [폼 제어 배열]
}
```
폼 제어 배열에 대해서는 지금부터 설명하겠습니다. 폼 제어는 다음과 같은 개체입니다:
```javascript
{
id: 'switch1',
type: 'switch',
label: 'Enable hoge',
value: false
}
```
`id` ... 제어 ID. `type` ... 제어 종류. 후술합니다. `label` ... 제어와 함께 표시할 텍스트. `value` ... 제어 기본값.
### 폼 조작값 받기
사용자가 폼을 조작하면, 스트림에서 `update-form` 이벤트가 발생합니다. 이벤트의 내용에는 제어 ID와 사용자가 설정한 값이 포함되어 있습니다. 예를 들어, 위에서 나타낸 스위치를 사용자가 켰다면, 다음 이벤트가 발생합니다:
```javascript
{
id: 'switch1',
value: true
}
```
### 폼 제어 종류
#### 스위치
type: `switch` 스위치를 표시합니다. 어떠한 기능을 켜거나 끄고 싶은 경우에 사용합니다.
##### 속성
`label` ... 스위치에 표시되는 텍스트.
#### 라디오 버튼
type: `radio` 라디오 버튼을 표시합니다. 선택지를 표시할 때 사용할 수 있습니다. 예를 들면, 봇의 난이도를 설정하는 등에 사용됩니다.
##### 속성
`items` ... 라디오 버튼 선택지. 예:
```javascript
items: [{
label: '약',
value: 1
}, {
label: '중',
value: 2
}, {
label: '강',
value: 3
}]
```
#### 슬라이더
type: `slider` 슬라이더를 표시합니다.
##### 속성
`min` ... 슬라이더의 최소값. `max` ... 슬라이더의 최대값. `step` ... 입력란에 기입되는 스텝 값.
#### 텍스트 상자
type: `textbox` 텍스트 상자를 표시합니다. 사용자에게 어떠한 것을 입력하도록 하는 일반적인 용도로 사용할 수 있습니다.
## 사용자에게 메시지 표시하기
설정 화면에서 사용자와 대화하는 것 이외에, 또 다른 방법입니다. 사용자에게 메시지를 표시할 수 있습니다. 예를 들어, 사용자가 봇이 지원하지 않는 모드나 지도를 선택했을 때, 경고를 표시하는 등으로 사용됩니다. 메시지를 표시하려면, 다음 메시지를 스트림으로 전송합니다:
```javascript
{
type: 'message',
body: {
text: '메시지 내용',
type: '메시지 종류'
}
}
```
메시지 종류: `success`, `info`, `warning`, `error`。
## 거두기
거두기를 하려면, <a href="./api/endpoints/games/reversi/games/surrender">이 엔드포인트</a>에 요청합니다.
|