게임 규칙
전략 해설 보기대결상대
TURN
ROUND
GAME
게임 로그
언제 죽고 언제 받을 것인가
섯다는 패를 고를 수 없는 게임입니다. 카드는 무작위로 오고, 내가 정하는 것은 걸 것인가 받을 것인가 죽을 것인가뿐입니다. 그래서 전략이 한 가지로 좁혀집니다. 언제 죽을 것인가. 그런데 죽는 데도 1원이 듭니다. 아래는 죽는 방식 셋과 각각이 실제로 낸 성적입니다.
1. 무엇이 걸렸든 받는다 (기본 샘플)
화면에 실려 있는 기본 코드가 이렇게 합니다. 내가 선이면 1원을 걸고, 그 밖에는 상대가 건 만큼 그대로 받습니다. 내 패를 보지 않습니다. 20장의 순위표가 이 화면 아래에 있는데 한 번도 쓰지 않습니다.
LEVEL 1 반반 LEVEL 2·3 열세
LEVEL 1과는 반반입니다. 그 상대도 1원만 걸고 절대 죽지 않아서 한 판에 오가는 돈이 1원뿐이기 때문입니다. 그런데 LEVEL 2·3은 강한 패를 들면 크게 올립니다. 패를 보지 않고 받으면 그 큰 금액을 계속 넣어 주게 됩니다.
2. 약하면 죽는다
두 장의 점수를 계산해서 5끗보다 낮으면 죽습니다. 패의 절반쯤을 버리는 값입니다. 점수 매기는 규칙은 이 화면 아래 순위표를 그대로 옮긴 것입니다.
var my_money = 0;
function onGameStart() {}
function onRoundStart(data) {
// my_money는 라운드가 시작될 때만 온다. 라운드 안에서는 직접 줄여 나간다.
my_money = data.my_money;
}
// 두 장의 점수. 이 화면 아래 순위표를 그대로 옮긴 것이다.
// 끗의 동점 규칙은 빼고 단순하게 잡았다.
function getPoint(c1, c2) {
var n1 = c1 > 10 ? c1 - 10 : c1;
var n2 = c2 > 10 ? c2 - 10 : c2;
if ((c1 === 3 && c2 === 8) || (c1 === 8 && c2 === 3)) { return 30000; }
if ((c1 === 1 && c2 === 8) || (c1 === 8 && c2 === 1)) { return 20000; }
if ((c1 === 1 && c2 === 3) || (c1 === 3 && c2 === 1)) { return 10000; }
if (n1 === n2) { return n1 * 1000; }
return ((c1 + c2) % 10) * 100;
}
function onTurnStart(data) {
var point = getPoint(data.my_cards[0], data.my_cards[1]);
var bet = data.op_turn_result;
var result;
if (point < 500) {
// 5끗보다 낮으면 죽는다. 패의 절반쯤을 버리는 값이다.
result = {action: "die", money: 1};
} else if (bet === null) {
result = my_money >= 2
? {action: "raise", money: 1}
: {action: "die", money: 1};
} else if (bet.money > my_money) {
result = {action: "die", money: 1};
} else {
result = {action: "call", money: bet.money};
}
my_money -= result.money;
return result;
}
function onRoundEnd() {}
function onGameEnd() {}
LEVEL 1 전패 LEVEL 2 우세 LEVEL 3 반반
LEVEL 2·3이 뒤집힙니다. 크게 걸어 올 때 약한 패를 버리니 큰 손해가 사라집니다. 그런데 가장 단순한 LEVEL 1에 전패합니다. 셋 중 유일하게 확률도 금액도 계산하지 않는 상대에게만 집니다. 여기가 이 게임에서 가장 이상한 지점입니다.
3. 죽는 것도 1원임을 계산에 넣는다
LEVEL 1은 1원만 걸고 절대 죽지 않습니다. 그 1원을 받는 값이 1원이고, 죽는 값도 1원입니다. 같습니다. 죽어서 아끼는 돈이 없는데 이길 기회만 버리는 것입니다. 이길 확률이 조금이라도 있으면 받는 편이 낫습니다. 버릴 패를 고르는 기준은 2번과 똑같이 두고, 조건 한 줄만 앞에 넣습니다.
op_turn_result.money == 1
죽어도 1원, 받아도 1원. 같으므로 받는다.
op_turn_result.money == 20
죽으면 1원, 받으면 20원. 다르므로 약한 패는 버린다.
var my_money = 0;
function onGameStart() {}
function onRoundStart(data) {
// my_money는 라운드가 시작될 때만 온다. 라운드 안에서는 직접 줄여 나간다.
my_money = data.my_money;
}
// 두 장의 점수. 이 화면 아래 순위표를 그대로 옮긴 것이다.
// 끗의 동점 규칙은 빼고 단순하게 잡았다.
function getPoint(c1, c2) {
var n1 = c1 > 10 ? c1 - 10 : c1;
var n2 = c2 > 10 ? c2 - 10 : c2;
if ((c1 === 3 && c2 === 8) || (c1 === 8 && c2 === 3)) { return 30000; }
if ((c1 === 1 && c2 === 8) || (c1 === 8 && c2 === 1)) { return 20000; }
if ((c1 === 1 && c2 === 3) || (c1 === 3 && c2 === 1)) { return 10000; }
if (n1 === n2) { return n1 * 1000; }
return ((c1 + c2) % 10) * 100;
}
function onTurnStart(data) {
var point = getPoint(data.my_cards[0], data.my_cards[1]);
var bet = data.op_turn_result;
var result;
if (bet === null) {
// 내가 선이다. 죽어도 1원이고 걸어도 1원이라 약한 패도 걸어 본다.
result = my_money >= 2
? {action: "raise", money: 1}
: {action: "die", money: 1};
} else if (bet.money > my_money) {
// 가진 돈보다 큰 금액은 낼 수 없다.
result = {action: "die", money: 1};
} else if (bet.money <= 1) {
// 받는 값이 죽는 값과 같다. 죽어서 아끼는 돈이 없으므로 받는다.
result = {action: "call", money: bet.money};
} else if (point >= 500) {
result = {action: "call", money: bet.money};
} else {
// 걸린 돈이 죽는 값보다 크다. 여기서부터만 약한 패를 버린다.
result = {action: "die", money: 1};
}
my_money -= result.money;
return result;
}
function onRoundEnd() {}
function onGameEnd() {}
LEVEL 1 반반 LEVEL 2 우세 LEVEL 3 반반
LEVEL 1이 전패에서 반반으로 돌아오고, LEVEL 2·3의 성적은 그대로입니다. 약한 패의 기준은 5끗 그대로입니다. 버릴지 말지를 걸린 돈과 비교하기 시작한 것뿐입니다. 죽는 것은 공짜가 아니고, 그렇다고 늘 같은 값도 아닙니다.
4. 여기서부터는 당신 차례
위 셋은 두 가지를 아예 쓰지 않았습니다. 하나는 상대의 첫 장입니다. onTurnStart가 받는 data.op_card로 상대 카드 한 장이 보입니다. 남은 카드 중 무엇이 붙어야 내 패를 넘는지 세면 이길 확률이 나옵니다. LEVEL 2가 그것을 합니다. 다른 하나는 금액입니다. 위 셋은 언제나 1원만 걸었습니다. 강한 패로 크게 걸면 더 벌고, 약한 패로 크게 걸면 상대가 죽을 수도 있습니다. 다만 상대가 죽지 않으면 그만큼 크게 잃습니다. 위 코드를 에디터에 붙여 넣고 여기서부터 고쳐 보세요.
대전은 이렇게 돕니다
- 코드배틀은 내가 작성한 코드와 상대가 작성한 코드가 일대일로 대결하는 방식이며, 언어는 JAVASCRIPT 입니다.
- 코드를 작성하고, 대결상대를 LEVEL1, LEVEL2, LEVEL3, 온라인 상대 중에서 선택한 후 게임시작 버튼을 누르면 대결이 시작됩니다.
- 대결은 game이며, 1 game은 최대 200번의 round로 구성되는데 round가 반복되는 동안 나 또는 상대의 money가 모두 떨어지면 game이 끝납니다. 그리고, 1 round는 몇번의 turn으로 구성되는데 각각의 턴에서, raise를 하여 table money를 올리고 상대의 turn으로 넘기거나, call 또는 die를 하여 round를 끝낼 수 있습니다.
- game의 시작과 끝에서 onGameStart, onGameEnd 함수가 호출되고, 각 round의 시작과 끝에서 onRoundStart, onRoundEnd 함수가 호출되며, 각 turn에서 onTurnStart 함수가 호출됩니다. onGameStart => onRoundStart => onTurnStart => onRoundEnd => onGameEnd. 사용자는 각 함수에 자신의 로직을 구현하면 됩니다.
| 서열 | 종류 | 이름 | 설명 |
|---|---|---|---|
| 1위 | 광땡 | 38광땡 | 카드 2장이 3과 8일때, 섯다 최강의 조합 |
| 2위 | 광땡 | 18광땡 | 카드 2장이 1과 8일때 |
| 3위 | 광땡 | 13광땡 | 카드 2장이 1과 3일때 |
| 4위 | 땡 | 장땡 | 카드 2장이 10과 20일때 |
| 5위 | 땡 | 9땡 | 카드 2장이 9와 19일때 |
| 6위 | 땡 | 8땡 | 카드 2장이 8와 18일때 |
| 7위 | 땡 | 7땡 | 카드 2장이 7와 17일때 |
| 8위 | 땡 | 6땡 | 카드 2장이 6와 16일때 |
| 9위 | 땡 | 5땡 | 카드 2장이 5와 15일때 |
| 10위 | 땡 | 4땡 | 카드 2장이 4와 14일때 |
| 11위 | 땡 | 3땡 | 카드 2장이 3와 13일때 |
| 12위 | 땡 | 2땡 | 카드 2장이 2와 12일때 |
| 13위 | 땡 | 1땡 | 카드 2장이 1와 11일때 |
| 14위 | 끗 | 9끗 | 카드 2장의 합의 일의 자리가 9인 경우. (예: 5와 14, 또는 3과 6 등). 끗이 같으면 큰수가 더 큰쪽이 승리. |
| 15위 | 끗 | 8끗 | 카드 2장의 합의 일의 자리가 8인 경우. (예: 5와 13, 또는 6과 2 등) |
| 16위 | 끗 | 7끗 | 카드 2장의 합의 일의 자리가 7인 경우. (예: 2와 15, 또는 3과 4 등) |
| 17위 | 끗 | 6끗 | 카드 2장의 합의 일의 자리가 6인 경우. (예: 5와 11, 또는 1과 5 등) |
| 18위 | 끗 | 5끗 | 카드 2장의 합의 일의 자리가 5인 경우. (예: 2와 13, 또는 3과 2 등) |
| 19위 | 끗 | 4끗 | 카드 2장의 합의 일의 자리가 4인 경우. (예: 4와 10, 또는 1과 3 등) |
| 20위 | 끗 | 3끗 | 카드 2장의 합의 일의 자리가 3인 경우. (예: 1과 12, 또는 2와 1 등) |
| 21위 | 끗 | 2끗 | 카드 2장의 합의 일의 자리가 2인 경우. (예: 2와 10, 또는 3과 9 등) |
| 22위 | 끗 | 1끗 | 카드 2장의 합의 일의 자리가 1인 경우. (예: 1과 10, 또는 5와 6 등) |
| 23위 | 끗 | 망통 | 카드 2장의 합의 일의 자리가 0인 경우. (예: 1과 9, 또는 3과 7 등) |
섯다는 훅이 다섯 개이고 onTurnEnd가 없습니다. onTurnStart가 action과 money를 담은 객체를 돌려줘야 하며 action은 raise·call·die 중 하나입니다. 첫 턴에는 call을 낼 수 없습니다. 위 2·3번 코드는 다섯 개를 모두 담고 있어 그대로 붙여 넣으면 돌아갑니다.
그리고 my_money는 라운드가 시작될 때만 옵니다. 라운드 안에서 낸 돈은 직접 빼 두어야 합니다. 그러지 않으면 가진 것보다 많이 걸어 실격됩니다. 죽는 데도 1원이 드니 마지막 한 푼까지 걸면 다음 턴에는 죽을 수조차 없습니다. 실격은 화면에서 그냥 패배로 보이기 때문에 찾기 어렵습니다.
성적은 상대별로 150판을 돌려 측정했고 저장소의 테스트가 실제 규칙 엔진으로 매번 다시 확인합니다. 한 판은 최대 200라운드입니다. 여기서 전패는 승률 3% 이하, 열세는 15% 이하, 반반은 20~80%, 우세는 50% 이상을 뜻합니다. 60판으로 재던 동안 3번 방식의 LEVEL 2 승률이 53%와 67% 사이를 오갔고, 우세의 경계가 50%라서 150판으로 올렸습니다.