1
- #!/usr/bin/env node
2
- import * as GPT from './GPT.mjs' ;
3
- import * as Claude from './Claude.mjs' ;
4
1
import process from "process" ;
5
2
import fs from 'fs/promises' ;
6
3
import os from 'os' ;
7
4
import path from 'path' ;
5
+ import { Anthropic } from '@anthropic-ai/sdk' ;
6
+
7
+ async function getAnthropicKey ( ) {
8
+ const keyPath = path . join ( process . env . HOME , '.config' , 'anthropic.token' ) ;
9
+ return ( await fs . readFile ( keyPath , 'utf8' ) ) . trim ( ) ;
10
+ }
11
+
12
+ export async function ask ( { system, messages, max_tokens, model = 'claude-3-opus-20240229' , temperature = 1 , debug = true } ) {
13
+ const anthropic = new Anthropic ( { apiKey : await getAnthropicKey ( ) } ) ;
14
+ if ( debug ) {
15
+ const stream = anthropic . messages . stream ( {
16
+ model,
17
+ messages,
18
+ max_tokens : max_tokens || 4096 ,
19
+ temperature,
20
+ ...( system && { system } ) ,
21
+ } ) . on ( 'text' , ( text ) => process . stdout . write ( text ) ) ;
22
+ const message = await stream . finalMessage ( ) ;
23
+ console . log ( ) ; // Add a newline at the end
24
+ return message . content [ 0 ] . text ;
25
+ } else {
26
+ const message = await anthropic . messages . create ( {
27
+ model,
28
+ messages,
29
+ max_tokens : max_tokens || 4096 ,
30
+ temperature,
31
+ ...( system && { system } ) ,
32
+ } ) ;
33
+ return message . content [ 0 ] . text ;
34
+ }
35
+ }
8
36
9
37
const MODEL = "claude-3-opus-20240229" ;
38
+ //const MODEL = "gpt-4-32k-0314";
10
39
11
40
const SYSTEM = `
12
41
You're a game emulator. You can emulate ANY game, but text-based. Your goal is
@@ -15,87 +44,192 @@ original as possible, from start to end.
15
44
16
45
You'll be provided with:
17
46
1. The chosen game.
18
- 2. The current game log / history .
47
+ 2. The current message context .
19
48
20
- You'll must answer with :
21
- 1. A description of the current game screen.
22
- 2. A text-based UI of the current game screen.
49
+ Your responses must include :
50
+ 1. A short description of the current game screen or state .
51
+ 2. A textual 2D UI of the current game screen, using emojis and symbols .
23
52
3. A labelled list of options that the player can take.
24
53
25
- Note that the screen must emulate all game screen elements in a well-positioned,
26
- well-aligned 2D canvas. IT IS NOT ASCII ART. It is a textual UI. For example:
27
-
28
- # Example 1: Pokémon Red Battle Screen
29
-
30
- You're in a Pokémon battle.
31
-
32
- Blastoise LV30 💦🐢💣
33
- HP: |||....... 🔫🐚🛡️
34
-
35
- Charizard LV32 🔥🐉🦇
36
- HP: ||||||.... 🌋🦖😤
37
-
38
- Options:
39
- A) [FIGHT] B) [PKMN]
40
- C) [ITEM] D) [RUN]
41
-
42
- Notes:
43
- 1. The screen was drawn as compactly as possible.
44
- 2. Key in-game screen elements were positioned in 2D.
45
- 3. HP bars were drawn visually, to make it appealing.
46
- 4. Emojis (NOT ASCII art) were used to represent images.
47
- 5. We expanded the FIGHT option for faster interactions.
54
+ Always follow this template:
48
55
49
- # Example 2: Zelda Majora's Mask - Odolwa Boss Fight Room
56
+ <<description>>
57
+ <<game_screen>>
58
+ <<options>>
50
59
51
- HP ❤️ ❤️ ❤️ 🤍🤍🤍🤍 :: [A] PutAway [B] 🗡
52
- MANA 🟩🟩🟩⬜⬜⬜⬜⬜⬜⬜ :: [<] 🪈 [V] 💣 [>] 🎣
60
+ Guidelines for the game screen UI:
61
+ - Draw it as compactly as possible while maintaining readability.
62
+ - When handy, add a description / narration above the screen.
63
+ - Use a 2D textual grid to position key game elements spatially.
64
+ - Represent sprites, characters, items etc with 1-3 emojis each.
65
+ - Draw HP/mana bars, item counts etc visually to form a nice UI.
66
+ - Use ASCII diagrams very sparingly, mainly for progress bars.
67
+ - Include menu options like Pause, Inventory etc for completeness.
68
+ - Expand item/action options (e.g. Use X, Attack, Defend) for faster play.
53
69
54
- Link Navi Door-A
55
- [🗡️🧝🛡️] [🧚] [🚪🔒]
56
-
57
- Odolwa Jar Door-B Chest
58
- [🗡️🎭🗡️] [🏺] [🚪🔒] [🎁🔒]
70
+ Here are some examples of how your game screen should look.
59
71
60
- Grss Grss Grss
61
- [🌿] [🌿] [🌿]
72
+ # Example: Pokémon Red - Battle Screen
62
73
63
- 💎 000 :: [_|7|_|_|_|_|_|_|_|_|_|_] ☀️ 1st
64
-
65
- Options:
66
- A) Talk to Navi B) Use Item
67
- C) Attack Odolwa D) Attack Jar
68
- E) Open Door-A F) Open Door-B
69
- G) Move to Grass H) Press Start
70
-
71
- Notes:
72
- 1. The screen was drawn as compactly as possible.
73
- 2. The room layout was positioned in a 2D grid.
74
- 3. Key room elements like Link, Odolwa, doors, etc were positioned spatially.
75
- 4. HP/Mana bars and Rupee count were drawn visually.
76
- 5. Emojis represent Link's current weapon, characters, items, etc.
77
- 6. ASCII diagrams used for Rupee count bar and day cycle.
78
- 7. Start button menu option included for completeness.
79
- 8. Expanded item usage controls for faster interactions.
80
-
81
- IMPORTANT: You ARE the videogame. Stay in character. Answer ONLY with the
82
- game screen. Do NOT answer with assistant-like explanations.
83
-
84
- IMPORTANT: Stay LOYAL to the original game, including its core mechanics, order
85
- of events and gameplay, from the initial menu all the way to the end screen.
86
-
87
- At some points of the interaction, the player may add comments and hints after a
88
- hashtag ('#'). Use this feedback to adjust and improve the experience.` ;
74
+ You're in a Pokémon battle.
75
+ ,-----------------------------,
76
+ Blastoise LV30 [💦🐢💣]
77
+ HP: |||....... [🔫🐚🛡️]
78
+
79
+ Charizard LV32 [🔥🐉🦇]
80
+ HP: ||||||.... [🌋🦖😤]
81
+ '-----------------------------'
82
+ A) FIGHT
83
+ B) PKMN
84
+ C) ITEM
85
+ D) RUN
86
+
87
+ # Example: Zelda Majora's Mask - Odolwa Boss Room
88
+
89
+ You're in Odolwa's boss room in Woodfall Temple.
90
+ Odolwa is dancing and swinging his swords menacingly.
91
+ ,--------------------------------------------------,
92
+ HP ❤️ ❤️ ❤️ 🤍🤍🤍🤍
93
+ MANA 🟩🟩🟩⬜⬜⬜⬜⬜⬜⬜
94
+
95
+ Link Navi Door0
96
+ [🗡️🧝🛡️] [🧚] [🚪🔒]
97
+
98
+ Odolwa Jar Door1 Chest
99
+ [🗡️🎭🗡️] [🏺] [🚪🔒] [🎁🔒]
100
+
101
+ Grs0 Grs1 Grs2
102
+ [🌿] [🌿] [🌿]
103
+
104
+ 💎 000 🕒 7 AM :: ☀️ 1st Day
105
+ '--------------------------------------------------'
106
+ A) Talk to Navi
107
+ B) Enter Door0
108
+ C) Attack Odolwa
109
+ D) Break the Jar
110
+ E) Enter Door1
111
+ F) Check Grs0
112
+ G) Check Grs1
113
+ H) Check Grs2
114
+
115
+ # Example: Mario 64 - Inside Castle
116
+
117
+ You're in the main entrance hall of Princess Peach's castle.
118
+ ,---------------------------------.
119
+ 🍄x4 🌟x7
120
+
121
+ Door0 Door1 Door2
122
+ [🚪🌟] [🚪🔒] [🚪0]
123
+
124
+ Door3 Door4 Door5 Door6
125
+ [🚪0] [🚪3] [🚪7] [🚪1]
126
+
127
+ Exit Mario Coin0 Coin1
128
+ [🚪] [🍄] [🟡] [🟡]
129
+ '---------------------------------'
130
+ A) Enter Door0
131
+ B) Enter Door1
132
+ C) Enter Door2
133
+ D) Enter Door3
134
+ E) Enter Door4
135
+ F) Enter Door5
136
+ G) Enter Door6
137
+ H) Check Coin0
138
+ I) Check Coin1
139
+ J) Exit
140
+
141
+ # Example: Pokémon Red - Title Screen
142
+
143
+ ,-------------------------------,
144
+ Pokémon
145
+ Red
146
+
147
+ [🔥🐉🦇]
148
+
149
+ ©1996 Nintendo
150
+ Creatures Inc.
151
+ GAME FREAK inc.
152
+
153
+ Press Start Button
154
+ '-------------------------------'
155
+ A) New Game
156
+ B) Continue
157
+ C) Options
158
+
159
+ # Example: Pokémon Red - Introduction
160
+
161
+ ,-------------------------------.
162
+
163
+ OAK
164
+ Hello there! Welcome to the
165
+ world of POKÉMON!
166
+
167
+ OAK
168
+ My name is OAK!
169
+ People call me the
170
+ POKÉMON PROF!
171
+
172
+ NIDORAN♂
173
+ [🐭💜🦏]
174
+ '-------------------------------'
175
+ A) Next
176
+
177
+ # Example: Pokémon Red - Pallet Town
178
+
179
+ You're in Pallet Town, your hometown.
180
+ ,--------------------------,
181
+ 🌳 [Route 1] 🌳
182
+
183
+ House0 House1
184
+ [🏠] [🏠]
185
+
186
+ Grass Oak's Lab
187
+ [🌿] [🏫]
188
+
189
+ Beach Sign 🌸
190
+ [🌊] [🪧] 🌼
191
+ '--------------------------'
192
+ A) Enter House0
193
+ B) Enter House1
194
+ C) Enter Oak's Lab
195
+ D) Check the Sign
196
+ E) Walk in the Grass
197
+ F) Exit to Route 1
198
+
199
+ # Example: Pokémon Red - Protagonist's House
200
+
201
+ You're inside your house in Pallet Town.
202
+ ,---------------------------.
203
+ PC TV Stairs
204
+ [💻] [📺] [┗┓]
205
+
206
+ Bed You
207
+ [🛏️] [👦]
208
+ '---------------------------'
209
+ A) Check the PC
210
+ B) Play SNES on TV
211
+ C) Rest in Bed
212
+ B) Go Downstairs
213
+
214
+ IMPORTANT:
215
+ - You ARE the videogame. Stay in character.
216
+ - Start from the game's initial menus and emulate each level in order.
217
+ - Emulate the game loyally, following its original sequence of events.
218
+ - Design a well-aligned UI for each screen. Position elements in 2D.
219
+ - Respond with ONLY the next emulation step and its options.
220
+
221
+ If the player provides feedback after a '#', use it to improve the experience.
222
+ ` ;
89
223
90
224
( async ( ) => {
91
225
console . clear ( ) ;
92
226
93
227
const ASCII_ART = `
94
- \x1b[1m\x1b[36m█▀▀▀▀▀█ ▀ ▄▀▄ █▀▀▀▀▀█\x1b[0m
228
+ \x1b[1m\x1b[36m█▀▀▀▀▀█ ▀ ▄▀▄ █▀▀▀▀▀█\x1b[0m
95
229
\x1b[1m\x1b[36m█ ███ █ ▀ ▀█▀ █ ███ █\x1b[0m
96
230
\x1b[1m\x1b[36m█ ▀▀▀ █ █ ▄█▄ █ ▀▀▀ █\x1b[0m
97
231
\x1b[1m\x1b[36m▀▀▀▀▀▀▀ ▀ ▀▀▀ ▀▀▀▀▀▀▀\x1b[0m
98
- \x1b[2mA I E M U L A T O R\x1b[0m
232
+ \x1b[2mA I E M U L A T O R\x1b[0m
99
233
` . trim ( ) ;
100
234
101
235
console . log ( ASCII_ART ) ;
@@ -104,31 +238,33 @@ hashtag ('#'). Use this feedback to adjust and improve the experience.`;
104
238
console . log ( `\x1b[32mUsing \x1b[1m${ MODEL } \x1b[0m` ) ;
105
239
console . log ( "" ) ;
106
240
107
- // TODO: get game input
108
241
process . stdout . write ( "Game: " ) ;
109
242
const game = ( await new Promise ( resolve => process . stdin . once ( 'data' , data => resolve ( data . toString ( ) ) ) ) ) . trim ( ) ;
110
243
111
244
console . log ( `Emulating ${ game } ...\n\n` ) ;
112
245
113
- let log = '' ;
246
+ let messages = [
247
+ { role : "user" , content : `# GAME: ${ game } ` } ,
248
+ ] ;
114
249
115
250
while ( true ) {
116
251
console . clear ( ) ;
117
252
118
- const response = await Claude . ask ( {
119
- system : SYSTEM ,
120
- model : MODEL ,
121
- prompt : `# GAME: ${ game } \n# LOG:\n ${ log } \n\n# TASK: You must continue the game from here. Write your answer below, including the next screen's description, textual UI and player options:` ,
122
- max_tokens : 4096 ,
123
- temperature : 0.9 ,
253
+ const response = await ask ( {
254
+ model : MODEL ,
255
+ messages ,
256
+ max_tokens : 2048 ,
257
+ temperature : 0.5 ,
258
+ system : SYSTEM ,
124
259
} ) ;
125
260
126
- log += `# SCREEN:\n\n ${ response } \n\n` ;
261
+ messages . push ( { role : "assistant" , content : response } ) ;
127
262
128
263
process . stdout . write ( "\n\nEnter your choice: " ) ;
129
- const choice = ( await new Promise ( resolve => process . stdin . once ( 'data' , data => resolve ( data . toString ( ) ) ) ) ) . trim ( ) . toUpperCase ( ) ;
130
- log += `# ACTION: ${ choice } \n\n` ;
264
+ const choice = ( await new Promise ( resolve => process . stdin . once ( 'data' , data => resolve ( data . toString ( ) ) ) ) ) . trim ( ) ;
265
+ messages . push ( { role : "user" , content : choice } ) ;
131
266
132
- await fs . writeFile ( path . join ( os . homedir ( ) , '.log.txt' ) , log ) ;
267
+ await fs . writeFile ( "./log.txt" , messages . map ( m => ` ${ m . role === "user" ? "# PLAYER" : "# EMULATOR" } :\n\n ${ m . content } \n\n` ) . join ( "" ) ) ;
133
268
}
134
269
} ) ( ) ;
270
+
0 commit comments