νΌλ μ΄λ AIλ νΌλ μ΄λ κ²μμ μ¬λ νλ μ΄μ΄ μΈμ AI λ΄μ μΆκ°νλ κΈ°λ₯μ κ°λ°νκΈ° μν νλ‘μ νΈμ΄λ©°, μ΄ νμ΄μ§λ κ°λ¨ν μ€λͺ κ³Ό νν 리μΌμ ν¬ν¨ν©λλ€. νΌλ μ΄λ κ²μμ νλ μ΄νλ μ¬λ¬κ°μ§ κ°λ₯ν μκ³ λ¦¬μ¦μ μμ±ν΄λ³΄κ³ , κ²½μμ μ°Έμ¬ν΄ κ°μ₯ λμ μ μλ₯Ό νλνμΈμ!
AI λ΄ κ°λ°μ μ¬μ©λλ νλ‘κ·Έλλ° μΈμ΄λ JavaScriptμ λλ€. Pythonμ μ¬μ©νλ©΄ μλλκ±ΈκΉ? νλ μκ°μ΄ λ λ€λ©΄, λ€μ μΈμ©κ΅¬λ₯Ό λ μ¬λ € λ΄ μλ€.
"Any application that can be written in JavaScript, will eventually be written in JavaScript."
λΉμ μ ν μ μμ΅λλ€.
νΌλ μ΄λλ₯Ό νλ μ΄νλ λ΄μ λ¨ λ κ°μ ν¨μλ‘ κ΅¬νν μ μμ΅λλ€. λμ μ°¨λ‘μ νΈλμμ λ¬΄μ¨ μΉ΄λλ₯Ό λΌμ§ κ²°μ νλ ν¨μ play_card()
μ, λ§μ§λ§ λΌμ΄λκ° λλκ³ νΈλμμ λ¬΄μ¨ μΉ΄λ λ μ₯μ λ΄λ €λμμ§ κ²°μ νλ ν¨μ play_hidden()
μ
λλ€.
play_card()
μ κ²°κ³Όκ°μ { 0, 1, 2, 3, 4 } μ€μ νλμ
λλ€.play_hidden()
μ κ²°κ³Όκ°μ { [0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3] } μ€μ νλμ
λλ€ (λ°°μ΄λ΄ μμλ 무κ΄ν©λλ€).μλ₯Ό λ€μ΄, μΈμ λ 무μμλ‘ νλ μ΄νλ λͺ¨μμ₯μμ μκ³ λ¦¬μ¦μ λ€μκ³Ό κ°μ΅λλ€.
function play_card() {
// Math.random()μ [0, 1) ꡬκ°μ μ€μλ₯Ό λ°νν¨
return Math.floor(Math.random() * 5);
}
function play_hidden() {
// [0, 1, 2, 3]μ μ
ννμ¬ μμ λ μμλ§ μ·¨ν¨
return [0, 1, 2, 3].sort(() => Math.random() - .5).slice(0, 2);
}
무μμλ‘ νλ μ΄νλ κ²λ³΄λ€ μνκ³ μΆλ€λ©΄, μ£Όμ΄μ§ μ 보λ₯Ό νμ©ν΄μΌ ν©λλ€. play_card()
μ play_hidden()
ν¨μμλ μ¬μ€ 첫λ²μ§Έμ΄μ μ μΌν μΈμ(state
)λ‘ νλ μ΄μ΄ μ
μ₯μμ νμ¬ κ²μμμ κ΄μΈ‘ κ°λ₯ν μ λ³΄κ° μ£Όμ΄μ§λλ€.
μ΄ μΈμ(state
)μλ λ€μκ³Ό κ°μ μ λ³΄κ° λ€μ΄ μμ΅λλ€.
{
num_players: 3, // νλ μ΄μ΄ μ
stack_size: 43, // λ¨μ λλ‘μ° μ
parade: [37, 61, 9, 4, 3, 27], // νΌλ μ΄λμ λμΈ μΉ΄λ
scores: [[], [45, 55], []], // μ§κΈκΉμ§ νλν μ μ
hand: [5, 8, 22, 44, 64], // λμ μν¨
history: [ // μ§κΈκΉμ§ νλ μ΄ κΈ°λ‘
{
player: 1, // νλ μ΄μ΄ λ²νΈ
card: 3, // μ νν μΉ΄λ
scores: [45, 55], // ν΄λΉ ν΄μ μ»μ μ μ
},
{
player: 2,
card: 27,
scores: [], // ν΄λΉ ν΄μ μ μ μ»μ§ μμ
},
],
is_last_round: false, // λ§μ§λ§ λΌμ΄λ
}
μμ μμλ κ²μμ μμνκ³ μμ λ€λ₯Έ μ¬λλ€(player: 1, player: 2)μ΄ νλ²μ©, μ΄ λν΄ νλ μ΄ ν λ΄κ° νλ μ΄ν μ°¨λ‘μΈ μν©μ
λλ€. νλ μ΄μ΄μ ꡬλΆμ λλ‘λΆν° 0μΌλ‘ μμν΄ μκ³ λ°©ν₯μΌλ‘(= μ΄μ΄μ νλ μ΄νλ μ°¨λ‘λλ‘) 1, 2, ..., (num_players
- 1)μ΄ λ©λλ€. κ²μμ 첫 ν΄ νλ μ΄μ΄μ κ΄κ³ μμ΄ λ΄κ° player: 0μ΄λ©°, μ 체 νλ μ΄μ΄κ° μ§κΈκΉμ§ νλν μ μλ₯Ό λνλ΄λ scores
μμλ 0λ²μ§Έ μμμΈ λ°°μ΄(scores[0]
)μ΄ λμ μ μλ₯Ό λνλ
λλ€.
parade, scores, hand, history.card, history.scores
λ±μ λ±μ₯νλ μ«μλ 0μμ 65 μ¬μ΄λ‘, κ° μ«μλ μΉ΄λ ν μ₯μ μκΉκ³Ό ν¬κΈ°λ₯Ό μλ―Έν©λλ€. μ«μλ₯Ό 11λ‘ λλ λͺ«μ΄ μκΉμ λνλ΄κ³ 11λ‘ λλ λλ¨Έμ§κ° ν¬κΈ°λ₯Ό λνλ
λλ€. μκΉμ μ«μλ₯Ό 11λ‘ λλ λͺ«μ λ°λΌ κ°κ° 0:νλ, 1:μ΄λ‘, 2:λ
Έλ, 3:λΉ¨κ°, 4:보λΌ, 5:κ²μ μ
λλ€. μλ₯Ό λ€μ΄, scores[1] = [45, 55]
λ player: 1μ μ μ 보λΌμ 1κ³Ό κ²μ μ 0 μΉ΄λλ₯Ό μλ―Έν©λλ€.
parade
μ hand
μ μ 보λ₯Ό μ‘°ν©νλ©΄ μν¨μ { 0, 1, 2, 3, 4 } μ€ μ΄λ€ μΉ΄λλ₯Ό λ΄λ κ²μ΄ μ 리ν μ§ κ³μ°ν μ μμ΅λλ€. λν, scores
λ₯Ό ν΅ν΄ κ²μμ νμΈμ ν₯λ°©μ κ°λ ν μ μμ΅λλ€.
μμ ν κ²κ³Ό κ°μ΄, μΈμμ μ 보λ₯Ό μ΄μ©ν΄ μΈλΆμ μΈ μ λ΅μ ꡬμν μ μμ΅λλ€. μλλ μ΄ν΄λ₯Ό λκΈ° μν JavaScript ꡬ문μ μμμ λλ€.
// κΈ΄ λ²μ
var color = 2,
counts = 0;
for (var i = 0; i < state.scores[0].length; i += 1) {
// parseIntλ μ€μμ μ μλΆλ§μ μ·¨ν¨
if (parseInt(state.scores[0][i] / 11) === color) {
counts += 1;
}
}
// 짧μ λ²μ
var counts = state.scores[0].filter(e => parseInt(e / 11) === 2).length;
// κΈ΄ λ²μ
var minimum = Infinity; // Infinity λμ μΆ©λΆν ν° μμμ μλ₯Ό μ¬μ©ν΄λ λ¨
for (var i = 0; i < state.hand.length; i += 1) {
var size = state.hand[i] % 11;
if (size < minimum) {
minimum = state.hand[i] % 11;
}
}
// 짧μ λ²μ
var minimum = Math.min.apply(null, state.hand.map(e => e % 11));
// λλ€λ₯Έ 짧μ λ²μ
var minimum = state.hand.map(e => e % 11).reduce((a, b) => Math.min(a, b), Infinity);
// κΈ΄ λ²μ
var card = 42,
expected_scores = [];
var color = parseInt(card / 11),
size = card % 11;
for (var i = 0; i < state.parade.length - size; i += 1) {
if (parseInt(state.parade[i] / 11) === color || state.parade[i] % 11 <= size) {
expected_scores.push(state.parade[i]);
}
}
// 짧μ λ²μ
var card = 42;
var expected_scores = state.parade
.filter(e => state.parade.indexOf(e) < state.parade.length - (card % 11)) // λ§μ€νΉ
.filter(e => parseInt(e / 11) === parseInt(card / 11) || e % 11 <= card % 11); // λ°μ³λκ° μΉ΄λ
var threshold = [];
for (var i = 0; i < 6; i += 1) {
var counts = state.scores.map(e => e.filter(e => parseInt(e / 11) === i)).map(e => e.length),
minimum = counts.reduce((a, b) => Math.min(a, b), 11),
maximum = counts.reduce((a, b) => Math.max(a, b), 0);
threshold.push(state.num_players === 2 ? minimum + 2 : maximum); // 2μΈμΌ κ²½μ° μ΅μκ°+2λ‘, κ·ΈμΈ μ΅λκ°μΌλ‘
}
// κΈ΄ λ²μ
var disclosed = Array(6).fill(0);
for (var i = 0; i < state.parade.length; i += 1) {
// νΌλ μ΄λ
var color = parseInt(state.parade[i] / 11);
disclosed[color] += 1;
}
for (var i = 0; i < state.num_players; i += 1) {
// κ° νλ μ΄μ΄μ μ μ μΉ΄λ
for (var j = 0; j < state.scores[i].length; j += 1) {
var color = parseInt(state.scores[i][j] / 11);
disclosed[color] += 1;
}
}
for (var i = 0; i < state.hand.length; i += 1) {
// λ΄ μν¨
var color = parseInt(state.scores[i] / 11);
disclosed[color] += 1;
}
// 짧μ λ²μ
var disclosed = Array(6).fill(0).map((e, i) => state.parade
.concat(state.scores.reduce((a, b) => a.concat(b), []))
.concat(state.hand)
.filter(e => parseInt(e / 11) === i)
.length)
Array λ©μλμ μΈμλ‘ μ°μΈ νμ΄ν ν¨μμ νκΈ°λ²μ λν΄μλ λ€μ λ§ν¬ μ μ€λͺ μ μ°Έκ³ ν΄μ£ΌμΈμ.
μ΄μ μ€μ state μΈμλ₯Ό μ¬μ©νλλ‘ μμ±λ AI λ΄μ μ΄ν΄λ΄ μλ€. λ€μμ νμ μ΄λ² ν΄μ νλνλ μ μ μΉ΄λμ ν©μ μ΅μννλλ‘ νλ μ΄νλ μ¬μμ μκ³ λ¦¬μ¦μ λλ€. μ£Όμ΄μ§ ν΄μ νΌλ μ΄λμ κΉλ¦° μΉ΄λμ μν¨λ₯Ό λΉκ΅ν΄ μ΅μμ μ μλ§μ κ°μ Έμ€λ € νκ³ , λ§μ§λ§μ λ μ₯ λ΄λ €λμ μΉ΄λλ₯Ό κ³ λ₯Ό λλ ν¬κΈ°κ° μμ μΉ΄λλ₯Ό κ³¨λΌ λ΄λ €λμ΅λλ€. λμ²΄λ‘ μ μλ₯Ό μ κ² μ»κ² μ§λ§, μκΉ λ μ κ·μΉμ ν¬ν¨ν΄λ νλ μ΄λ₯Ό μ ν μ§λ λκ³ λ΄μΌ ν©λλ€. κ·Έλ¦¬κ³ λ§€ν΄ λμμ μ΄μ΅λ§μ μΆκ΅¬νλ κ² λν μ¬μμ μ½μ μ λλ€.
function play_card(state) {
var adds_numbers_sum = state.hand.map(card =>
state.parade
.filter(e => state.parade.indexOf(e) < state.parade.length - (card % 11)) // λ§μ€νΉ
.filter(e => parseInt(e / 11) === parseInt(card / 11) || e % 11 <= card % 11) // λ°μ³λκ° μΉ΄λ
.map(e => e % 11) // μ ν¬κΈ°
.reduce((a, b) => a + b, 0)); // μ ν©
var min = Math.min.apply(null, adds_numbers_sum),
argmin = adds_numbers_sum.indexOf(min);
return argmin;
}
function play_hidden(state) {
var numbers = state.hand.map(e => e % 11 + Math.random()); // λ
Έμ΄μ¦ μ λν΄μ£Όλ©΄ [0, 0] μ΄λ°μλ‘ μ ν
var sorted = Array.from(numbers).sort((a, b) => a - b), // sortλ inplace λ©μλλΌ deep copy
argmins = sorted.slice(0, 2).map(e => numbers.indexOf(e));
return argmins;
}
μ΄μ λΉμ μ νΌλ μ΄λμ κ²μ νλ μ΄ μκ³ λ¦¬μ¦μ μμ±ν μ€λΉκ° λͺ¨λ λλ¬μ΅λλ€. νμ΄μ λΉλλ€!
ν¨μμ κ²°κ³Όκ°μ΄ μ ν¨νμ§ μμ κ²½μ°(μμ: play_card()μ κ²°κ³Όκ°μ΄ 59) λλ κ³μ°μκ°μ΄ 1μ΄λ₯Ό μ΄κ³Όνκ±°λ μ§λμΉκ² λ§μ λ©λͺ¨λ¦¬λ₯Ό μ¬μ©νλ κ²½μ° κ²½μμμ μ μΈλ©λλ€. μμ±ν μκ³ λ¦¬μ¦μ λ³ΈμΈλ§ μ‘°ν λλ μμ κ°λ₯ν©λλ€. 보μμ μ΄μ λ‘ eval, Function, setTimeout, setInterval, promise, prototype, document λ±μ ν€μλ μ¬μ©μ κΈμ§ν©λλ€.