-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathocean_learning_database.py
More file actions
406 lines (343 loc) · 15 KB
/
Copy pathocean_learning_database.py
File metadata and controls
406 lines (343 loc) · 15 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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
#!/usr/bin/env python3
"""
🌊 OCEAN LEARNING DATABASE - Persistent Learning System
======================================================
This creates a persistent learning database that saves OCEAN's progress:
- Remembers all games played
- Saves learning patterns
- Maintains adaptation level
- Builds opponent profiles
- Never forgets what it learned
"""
import os
import json
import sqlite3
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional
logger = logging.getLogger(__name__)
class OceanLearningDatabase:
"""
🌊 OCEAN Learning Database - Persistent Learning System
Features:
- SQLite database for reliable storage
- Game history tracking
- Pattern recognition storage
- Opponent profiling
- Adaptation level persistence
- Performance metrics
"""
def __init__(self, db_path="ocean_learning.db"):
"""Initialize the learning database."""
self.db_path = db_path
self.connection = None
self._initialize_database()
logger.info("🌊 OCEAN Learning Database initialized")
def _initialize_database(self):
"""Initialize the SQLite database with required tables."""
self.connection = sqlite3.connect(self.db_path)
cursor = self.connection.cursor()
# Create tables
cursor.execute('''
CREATE TABLE IF NOT EXISTS games (
id INTEGER PRIMARY KEY AUTOINCREMENT,
game_id TEXT UNIQUE,
start_time TIMESTAMP,
end_time TIMESTAMP,
outcome TEXT,
move_count INTEGER,
opponent_type TEXT,
adaptation_level REAL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS moves (
id INTEGER PRIMARY KEY AUTOINCREMENT,
game_id TEXT,
move_number INTEGER,
player TEXT,
move_uci TEXT,
fen_before TEXT,
fen_after TEXT,
evaluation REAL,
game_phase TEXT,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (game_id) REFERENCES games (game_id)
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS patterns (
id INTEGER PRIMARY KEY AUTOINCREMENT,
pattern_type TEXT,
pattern_data TEXT,
success_rate REAL,
usage_count INTEGER,
last_used TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS opponent_profiles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
opponent_id TEXT UNIQUE,
total_games INTEGER,
wins INTEGER,
losses INTEGER,
draws INTEGER,
preferred_openings TEXT,
playing_style TEXT,
weakness_patterns TEXT,
last_played TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS learning_metrics (
id INTEGER PRIMARY KEY AUTOINCREMENT,
metric_name TEXT,
metric_value REAL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
self.connection.commit()
logger.info("📊 Database tables initialized")
def start_new_game(self, opponent_type="human"):
"""Start tracking a new game."""
game_id = f"game_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
cursor = self.connection.cursor()
cursor.execute('''
INSERT INTO games (game_id, start_time, opponent_type, adaptation_level)
VALUES (?, ?, ?, ?)
''', (game_id, datetime.now().isoformat(), opponent_type, self.get_adaptation_level()))
self.connection.commit()
logger.info(f"🎮 Started new game: {game_id}")
return game_id
def record_move(self, game_id, move_number, player, move_uci, fen_before, fen_after, evaluation=0.0, game_phase="middlegame"):
"""Record a move in the database."""
cursor = self.connection.cursor()
cursor.execute('''
INSERT INTO moves (game_id, move_number, player, move_uci, fen_before, fen_after, evaluation, game_phase)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', (game_id, move_number, player, move_uci, fen_before, fen_after, evaluation, game_phase))
self.connection.commit()
def end_game(self, game_id, outcome, move_count):
"""End a game and update statistics."""
cursor = self.connection.cursor()
cursor.execute('''
UPDATE games
SET end_time = ?, outcome = ?, move_count = ?
WHERE game_id = ?
''', (datetime.now().isoformat(), outcome, move_count, game_id))
# Update adaptation level based on outcome
self._update_adaptation_level(outcome)
# Update opponent profile
self._update_opponent_profile(game_id, outcome)
self.connection.commit()
logger.info(f"🏁 Game ended: {game_id} - {outcome}")
def _update_adaptation_level(self, outcome):
"""Update OCEAN's adaptation level based on game outcome."""
current_level = self.get_adaptation_level()
# Increase adaptation level based on performance
if outcome == "ocean_win":
new_level = min(1.0, current_level + 0.02) # 2% increase for wins
elif outcome == "human_win":
new_level = max(0.0, current_level - 0.01) # 1% decrease for losses
else: # draw
new_level = min(1.0, current_level + 0.005) # 0.5% increase for draws
self._save_metric("adaptation_level", new_level)
logger.info(f"🧠 Adaptation level updated: {current_level:.2f} → {new_level:.2f}")
def _update_opponent_profile(self, game_id, outcome):
"""Update opponent profile based on game."""
cursor = self.connection.cursor()
# Get game moves to analyze opponent patterns
cursor.execute('SELECT move_uci, game_phase FROM moves WHERE game_id = ? AND player = ?', (game_id, "human"))
human_moves = cursor.fetchall()
if human_moves:
# Analyze patterns (simplified)
opening_moves = [move for move, phase in human_moves if phase == "opening"]
preferred_openings = self._analyze_openings(opening_moves)
# Update or create opponent profile
cursor.execute('SELECT id FROM opponent_profiles WHERE opponent_id = ?', ("default_human",))
if cursor.fetchone():
cursor.execute('''
UPDATE opponent_profiles
SET total_games = total_games + 1,
wins = wins + ?,
losses = losses + ?,
draws = draws + ?,
preferred_openings = ?,
last_played = ?
WHERE opponent_id = ?
''', (1 if outcome == "human_win" else 0,
1 if outcome == "ocean_win" else 0,
1 if outcome == "draw" else 0,
json.dumps(preferred_openings),
datetime.now().isoformat(),
"default_human"))
else:
cursor.execute('''
INSERT INTO opponent_profiles (opponent_id, total_games, wins, losses, draws, preferred_openings, last_played)
VALUES (?, 1, ?, ?, ?, ?, ?)
''', ("default_human",
1 if outcome == "human_win" else 0,
1 if outcome == "ocean_win" else 0,
1 if outcome == "draw" else 0,
json.dumps(preferred_openings),
datetime.now().isoformat()))
def _analyze_openings(self, opening_moves):
"""Analyze opening patterns from moves."""
if not opening_moves:
return []
# Simple opening analysis
opening_patterns = []
for move in opening_moves[:5]: # First 5 moves
if move.startswith('e4'):
opening_patterns.append("e4_openings")
elif move.startswith('d4'):
opening_patterns.append("d4_openings")
elif move.startswith('Nf3'):
opening_patterns.append("Nf3_openings")
return list(set(opening_patterns)) # Remove duplicates
def get_adaptation_level(self):
"""Get current adaptation level."""
cursor = self.connection.cursor()
cursor.execute('SELECT metric_value FROM learning_metrics WHERE metric_name = ? ORDER BY timestamp DESC LIMIT 1', ("adaptation_level",))
result = cursor.fetchone()
return result[0] if result else 0.0
def _save_metric(self, metric_name, metric_value):
"""Save a learning metric."""
cursor = self.connection.cursor()
cursor.execute('INSERT INTO learning_metrics (metric_name, metric_value) VALUES (?, ?)', (metric_name, metric_value))
self.connection.commit()
def get_opponent_profile(self, opponent_id="default_human"):
"""Get opponent profile."""
cursor = self.connection.cursor()
cursor.execute('SELECT * FROM opponent_profiles WHERE opponent_id = ?', (opponent_id,))
result = cursor.fetchone()
if result:
return {
'opponent_id': result[1],
'total_games': result[2],
'wins': result[3],
'losses': result[4],
'draws': result[5],
'preferred_openings': json.loads(result[6]) if result[6] else [],
'playing_style': result[7],
'weakness_patterns': json.loads(result[8]) if result[8] else [],
'last_played': result[9]
}
return None
def get_game_history(self, limit=10):
"""Get recent game history."""
cursor = self.connection.cursor()
cursor.execute('''
SELECT game_id, outcome, move_count, adaptation_level, start_time
FROM games
ORDER BY start_time DESC
LIMIT ?
''', (limit,))
games = []
for row in cursor.fetchall():
games.append({
'game_id': row[0],
'outcome': row[1],
'move_count': row[2],
'adaptation_level': row[3],
'start_time': row[4]
})
return games
def get_learning_statistics(self):
"""Get comprehensive learning statistics."""
cursor = self.connection.cursor()
# Total games
cursor.execute('SELECT COUNT(*) FROM games')
total_games = cursor.fetchone()[0]
# Win rate
cursor.execute('SELECT COUNT(*) FROM games WHERE outcome = ?', ("ocean_win",))
wins = cursor.fetchone()[0]
# Current adaptation level
adaptation_level = self.get_adaptation_level()
# Recent performance (last 10 games)
cursor.execute('''
SELECT outcome FROM games
ORDER BY start_time DESC
LIMIT 10
''')
recent_outcomes = [row[0] for row in cursor.fetchall()]
recent_wins = sum(1 for outcome in recent_outcomes if outcome == "ocean_win")
recent_performance = recent_wins / len(recent_outcomes) if recent_outcomes else 0.0
return {
'total_games': total_games,
'total_wins': wins,
'win_rate': wins / total_games if total_games > 0 else 0.0,
'adaptation_level': adaptation_level,
'recent_performance': recent_performance,
'games_analyzed': len(recent_outcomes)
}
def save_pattern(self, pattern_type, pattern_data, success_rate, usage_count=1):
"""Save a learned pattern."""
cursor = self.connection.cursor()
# Check if pattern already exists
cursor.execute('SELECT id FROM patterns WHERE pattern_type = ? AND pattern_data = ?', (pattern_type, pattern_data))
existing = cursor.fetchone()
if existing:
# Update existing pattern
cursor.execute('''
UPDATE patterns
SET success_rate = ?, usage_count = usage_count + ?, last_used = ?
WHERE id = ?
''', (success_rate, usage_count, datetime.now().isoformat(), existing[0]))
else:
# Insert new pattern
cursor.execute('''
INSERT INTO patterns (pattern_type, pattern_data, success_rate, usage_count, last_used)
VALUES (?, ?, ?, ?, ?)
''', (pattern_type, pattern_data, success_rate, usage_count, datetime.now().isoformat()))
self.connection.commit()
def get_patterns(self, pattern_type=None):
"""Get learned patterns."""
cursor = self.connection.cursor()
if pattern_type:
cursor.execute('SELECT * FROM patterns WHERE pattern_type = ? ORDER BY success_rate DESC', (pattern_type,))
else:
cursor.execute('SELECT * FROM patterns ORDER BY success_rate DESC')
patterns = []
for row in cursor.fetchall():
patterns.append({
'id': row[0],
'pattern_type': row[1],
'pattern_data': row[2],
'success_rate': row[3],
'usage_count': row[4],
'last_used': row[5]
})
return patterns
def close(self):
"""Close the database connection."""
if self.connection:
self.connection.close()
logger.info("🔒 Database connection closed")
# Global database instance
_learning_db = None
def get_learning_database():
"""Get the global learning database instance."""
global _learning_db
if _learning_db is None:
_learning_db = OceanLearningDatabase()
return _learning_db
def initialize_learning_database():
"""Initialize the learning database."""
return get_learning_database()
if __name__ == "__main__":
# Test the database
db = OceanLearningDatabase()
# Test game
game_id = db.start_new_game("test_human")
db.record_move(game_id, 1, "human", "e2e4", "start", "after_e4", 0.2, "opening")
db.record_move(game_id, 2, "ocean", "e7e5", "after_e4", "after_e5", -0.1, "opening")
db.end_game(game_id, "ocean_win", 2)
# Test statistics
stats = db.get_learning_statistics()
print(f"Learning Statistics: {stats}")
db.close()