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
import { agentHandler } from "https://esm.town/v/saolsen/gameplay_agent";
import {
COLS,
Connect4,
Connect4Action,
Connect4AgentResponse,
Connect4State,
} from "https://esm.town/v/saolsen/gameplay_connect4";
import { GameError, GameKind, ResultKind, StatusKind } from "https://esm.town/v/saolsen/gameplay_games";
const SIMULATIONS = 10000;
function rand_action(state: Connect4State): Connect4Action {
const player = state.active_player;
while (true) {
const column = Math.floor(Math.random() * COLS);
const action: Connect4Action = { column };
if (!(Connect4.checkAction(state, player, action) instanceof GameError)) {
return action;
}
}
}
function score_action(
current_state: Connect4State,
action: Connect4Action,
): number {
const player = current_state.active_player;
// Create a new match with the action applied.
const next_state = JSON.parse(JSON.stringify(current_state));
let status = Connect4.applyAction(next_state, player, action);
// Simulate random games from this state.
let score = 0;
for (let i = 0; i < SIMULATIONS; i++) {
const sim_state = JSON.parse(JSON.stringify(next_state));
// Play out the rest of the game randomly.
if (status instanceof GameError) {
throw status;
}
while (status.status === StatusKind.InProgress) {
const sim_action = rand_action(sim_state);
const next_status = Connect4.applyAction(
sim_state,
sim_state.active_player,
sim_action,
);
if (next_status instanceof GameError) {
throw next_status;
}
status = next_status;
}
if (status.result.kind === ResultKind.Winner) {
if (status.result.players.includes(player)) {
score += 1;
} else {
score -= 1;
}
}
}
return score / SIMULATIONS;
}
function agent(state: Connect4State): Connect4AgentResponse {
// For each action we could take, simulate multiple random games from the resulting state.
// Keep track of the number of wins for each action.
// Pick the action with the highest win rate.
let max_score = Number.MIN_VALUE;
let best_action: Connect4Action = { column: 0 };
for (let col = 0; col < COLS; col++) {
const action: Connect4Action = { column: col };
const check = Connect4.checkAction(state, state.active_player, action);
if (!(check instanceof GameError)) {
const score = score_action(state, action);
if (score > max_score) {
max_score = score;
best_action = action;
}
}
}
return { action: best_action };
}
export default agentHandler(
[
{
game: GameKind.Connect4,
agentname: "mcts",
agent: agent,
},
],
);
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
import { agentHandler } from "https://esm.town/v/saolsen/gameplay_agent";
import { GameKind, JsonObject } from "https://esm.town/v/saolsen/gameplay_games";
import {
PokerAction,
PokerActionKind,
PokerAgentResponse,
PokerView,
} from "https://esm.town/v/saolsen/gameplay_poker";
function agent(view: PokerView, _agent_data?: JsonObject): PokerAgentResponse {
const round = view.rounds[view.round];
const player = round.active_player;
const chips = view.player_chips[player];
const amount_to_call = round.bet - round.player_bets[player];
if (round.bet === 0) {
const action: PokerAction = { kind: PokerActionKind.Bet, amount: chips };
return { action };
} else if (amount_to_call >= chips) {
const action: PokerAction = { kind: PokerActionKind.Call };
return { action };
} else {
const raise_amount = chips - amount_to_call;
const action: PokerAction = {
kind: PokerActionKind.Raise,
amount: raise_amount,
};
return { action };
}
}
export default agentHandler(
[
{
game: GameKind.Poker,
agentname: "all_in",
agent: agent,
},
],
);
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
import { agentHandler } from "https://esm.town/v/saolsen/gameplay_agent";
import { GameKind, JsonObject } from "https://esm.town/v/saolsen/gameplay_games";
import {
PokerActionKind,
PokerAgentResponse,
PokerView,
} from "https://esm.town/v/saolsen/gameplay_poker";
function fold_action(
view: PokerView,
_agent_data?: JsonObject,
): PokerAgentResponse {
if (view.rounds[view.round].bet === 0) {
return { action: { kind: PokerActionKind.Check } };
}
return { action: { kind: PokerActionKind.Fold } };
}
export default agentHandler(
[
{
game: GameKind.Poker,
agentname: "folds",
agent: fold_action,
},
],
);
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
import { GameError, GameKind, JsonObject } from "https://esm.town/v/saolsen/gameplay_games";
import {
COLS,
Connect4,
Connect4Action,
Connect4AgentResponse,
Connect4State,
} from "https://esm.town/v/saolsen/gameplay_connect4";
import { agentHandler } from "https://esm.town/v/saolsen/gameplay_agent";
function rand_action(
state: Connect4State,
agent_data?: { counter: number },
): Connect4AgentResponse {
const counter = agent_data?.counter || 0;
const player = state.active_player;
while (true) {
const column = Math.floor(Math.random() * COLS);
const action: Connect4Action = { column };
if (!(Connect4.checkAction(state, player, action) instanceof GameError)) {
return { action, agent_data: { counter: counter + 1 } };
}
}
}
export default agentHandler(
[
{
game: GameKind.Connect4,
agentname: "rand",
agent: rand_action,
},
],
);
1
Next