This repository was archived by the owner on May 16, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathworker.js
More file actions
166 lines (140 loc) · 6.42 KB
/
Copy pathworker.js
File metadata and controls
166 lines (140 loc) · 6.42 KB
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
161
162
163
164
165
166
var worker_default = {
// 1. 定時実行 (Cron):8分ごとに修行
async scheduled(event, env, ctx) {
const randomPattern = Math.floor(Math.random() * 4);
const fakeRequest = new Request(`https://local/train?pattern=${randomPattern}`);
// worker_defaultを直接参照してfetchを呼び出す
await worker_default.fetch(fakeRequest, env);
},
async fetch(request, env) {
const { pathname, searchParams } = new URL(request.url);
const jsonHeader = {
"content-type": "application/json; charset=utf-8",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type"
};
if (request.method === "OPTIONS") {
return new Response(null, { headers: jsonHeader });
}
// 1. 設定確認 (DB接続確認)
const config = await env.DB.prepare("SELECT value FROM settings WHERE key = 'is_active'").first();
const isActive = config ? config.value === 1 : true;
if (!isActive && pathname !== "/start" && pathname !== "/status") {
return new Response(JSON.stringify({ status: "stopped", message: "System is paused." }), { status: 503, headers: jsonHeader });
}
// 2. システム操作
if (pathname === "/stop") {
await env.DB.prepare("UPDATE settings SET value = 0 WHERE key = 'is_active'").run();
return new Response(JSON.stringify({ status: "success", message: "System STOPPED" }), { headers: jsonHeader });
}
if (pathname === "/start") {
await env.DB.prepare("UPDATE settings SET value = 1 WHERE key = 'is_active'").run();
return new Response(JSON.stringify({ status: "success", message: "System STARTED" }), { headers: jsonHeader });
}
// 3. 統計・制限確認
const result = await env.DB.prepare(
"SELECT COUNT(*) as count FROM battle_history WHERE created_at > date('now')"
).first();
const todayCount = result ? result.count : 0;
if (pathname === "/status") {
const stats = await env.DB.prepare(`
SELECT mode, COUNT(*) as total,
ROUND(AVG(CASE WHEN reward > 0 THEN 1 ELSE 0 END) * 100, 1) as win_rate
FROM battle_history GROUP BY mode
`).all();
const brain = await env.DB.prepare("SELECT * FROM q_table ORDER BY state, q_value DESC").all();
return new Response(JSON.stringify({
status: isActive ? "running" : "stopped",
today_total: todayCount,
limit: 90000,
performance: stats.results || [],
ai_brain: brain.results || []
}, null, 2), { headers: jsonHeader });
}
if (todayCount > 90000) {
return new Response(JSON.stringify({ status: "error", message: "Daily limit reached" }), { status: 503, headers: jsonHeader });
}
// 4. 修行モード (/train)
if (pathname === "/train") {
const pattern = parseInt(searchParams.get("pattern") || "0");
const batchSize = 200;
const { results: q_rows } = await env.DB.prepare("SELECT * FROM q_table").all();
let q_map = {};
(q_rows || []).forEach((row) => {
q_map[`${row.state}-${row.action}`] = row.q_value;
});
let prevStateB = Math.floor(Math.random() * 3);
const statements = [];
for (let i = 0; i < batchSize; i++) {
let bestAction = 0;
let maxQ = -Infinity;
for (let a = 0; a < 3; a++) {
let val = q_map[`${prevStateB}-${a}`] || 0;
if (val > maxQ) {
maxQ = val;
bestAction = a;
}
}
let hand_b;
switch (pattern) {
case 1: hand_b = 0; break;
case 2: hand_b = (prevStateB + 2) % 3; break;
case 3: hand_b = i % 3; break;
default: hand_b = Math.floor(Math.random() * 3);
}
const judge = (bestAction - hand_b + 3) % 3;
const reward = judge === 2 ? 1 : judge === 1 ? -1 : 0;
const q_key = `${prevStateB}-${bestAction}`;
const oldQ = q_map[q_key] || 0;
q_map[q_key] = oldQ + 0.1 * (reward - oldQ);
statements.push(env.DB.prepare("INSERT INTO battle_history (mode, hand_a, hand_b, reward) VALUES ('train', ?, ?, ?)").bind(bestAction, hand_b, reward));
prevStateB = hand_b;
}
for (const key in q_map) {
const [s, a] = key.split("-").map(Number);
statements.push(env.DB.prepare("UPDATE q_table SET q_value = ? WHERE state = ? AND action = ?").bind(q_map[key], s, a));
}
await env.DB.batch(statements);
return new Response(JSON.stringify({ status: "success", pattern, today_total: todayCount + batchSize }), { headers: jsonHeader });
}
// 5. 対戦モード (/play)
if (pathname === "/play") {
// ユーザーの手の取得 (URLパラメータを柔軟に判定)
let handParam = searchParams.get("hand") || searchParams.get("h");
if (!handParam) {
const rawQuery = request.url.split('?')[1];
if (rawQuery && /^[0-2]$/.test(rawQuery)) {
handParam = rawQuery;
}
}
const userHand = parseInt(handParam ?? "0");
// AIの状態把握と意思決定
const last = await env.DB.prepare("SELECT hand_a FROM battle_history WHERE mode='test' ORDER BY id DESC LIMIT 1").first();
const state = last ? last.hand_a : 0;
let aiHand;
if (Math.random() < 0.1) { // 10%の確率でランダム(探索)
aiHand = Math.floor(Math.random() * 3);
} else {
const row = await env.DB.prepare("SELECT action FROM q_table WHERE state = ? ORDER BY q_value DESC, RANDOM() LIMIT 1").bind(state).first();
aiHand = row ? row.action : 0;
}
const judge = (aiHand - userHand + 3) % 3;
const reward = judge === 2 ? 1 : judge === 1 ? -1 : 0;
// DB更新
await env.DB.batch([
env.DB.prepare("UPDATE q_table SET q_value = q_value + 0.1 * (? - q_value) WHERE state = ? AND action = ?").bind(reward, state, aiHand),
env.DB.prepare("INSERT INTO battle_history (mode, hand_a, hand_b, reward) VALUES ('test', ?, ?, ?)").bind(aiHand, userHand, reward)
]);
const hands = ["グー", "チョキ", "パー"];
return new Response(JSON.stringify({
status: "success",
you: hands[userHand],
ai_hand: hands[aiHand],
result: reward > 0 ? "AI_WIN" : reward < 0 ? "USER_WIN" : "DRAW"
}), { headers: jsonHeader });
}
return new Response(JSON.stringify({ status: "ready" }), { headers: jsonHeader });
}
};
export default worker_default;