Account Name or Address / Txn Hash or Version / Block Height or Version

Account

0 APT

Balance

SCORE4

score4

11 entry functions | Bytecode: 5.71 KB


Code

The source code is plain text uploaded by the deployer, which can be different from the actual bytecode.

1module martian::score4 {
2    use std::error;
3    use std::string;
4    use std::vector;
5    use aptos_std::table::{Self, Table};
6    use std::signer;
7    use std::string::String;
8    use aptos_framework::account::SignerCapability;
9    use aptos_framework::resource_account;
10    use aptos_framework::timestamp;
11    use aptos_framework::coin;
12    use coordinator::coordinator::{Self, request};
13    use mint_nft::create_nft;
14    use aptos_framework::event;
15    use aptos_framework::aptos_coin::AptosCoin;
16
17    struct Game has key, store, drop {
18        game_id: u64,
19        expiration_timestamp: u64,
20        player_turn: bool,
21        player: address,
22        grid: vector<vector<u8>>,
23        winner_nft_prompt: String,
24    }
25
26    struct ModuleData has key {
27        signer_cap: SignerCapability,
28        module_enabled: bool,
29        games_count: u64,
30        request_count: u64,
31        games: Table<address, Game>, // address of user -> expiration timestamp
32        active_requests: Table<u64, bool>,
33        model_address: String,
34        usage_fee: u64,
35        fee_account: address,
36        admin_addresses: vector<address>,
37        mint_nft_model_address: String,
38    }
39
40    #[event]
41    struct GameEvent has drop, store {
42        game_id: u64,
43        player: address,
44        outcome: String, // 0 for draw, 1 for win and 2 for lose
45    }
46
47    const ENOT_AUTHORIZED: u64 = 1;
48    const EMODULE_DISABLED: u64 = 2;
49    const EMOVE_NOT_ALLOWED: u64 = 3;
50    const ECANNOT_START_GAME: u64 = 4;
51    const EGAME_EXPIRED: u64 = 5;
52    const EGAME_NOT_STARTED: u64 = 6;
53
54    fun init_module(resource_signer: &signer) {
55        let resource_signer_cap = resource_account::retrieve_resource_account_cap(resource_signer, @source_addr);
56        let admin_addresses = vector::empty();
57        vector::push_back(&mut admin_addresses, @admin_addr);
58        move_to(resource_signer, ModuleData {
59            signer_cap: resource_signer_cap,
60            module_enabled: true,
61            games_count: 0,
62            request_count: 0,
63            games: table::new<address, Game>(),
64            active_requests: table::new<u64, bool>(),
65            model_address: string::utf8(b"0x3"),
66            usage_fee: 1000000,
67            fee_account: @admin_addr,
68            admin_addresses: admin_addresses,
69            mint_nft_model_address: string::utf8(b"0x1"),
70        });
71    }
72
73    fun check_admin(caller: &signer) acquires ModuleData{
74        let module_data = borrow_global<ModuleData>(@martian);
75        let caller_address = signer::address_of(caller);
76        assert!(vector::contains(&module_data.admin_addresses, &caller_address), error::permission_denied(ENOT_AUTHORIZED));
77    }
78
79    public entry fun restart_game(caller: &signer) acquires ModuleData {
80        let module_data = borrow_global_mut<ModuleData>(@martian);
81        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
82        assert!(table::contains<address, Game>(&module_data.games, signer::address_of(caller)), error::permission_denied(EGAME_NOT_STARTED));
83        let game = table::borrow_mut(&mut module_data.games, signer::address_of(caller));
84        game.expiration_timestamp = timestamp::now_seconds() + 6000;
85        game.player_turn = true;
86        game.grid = vector::empty();
87        for (i in 0..6) {
88            let row = vector::empty();
89            for (j in 0..7) {
90                vector::push_back(&mut row, 0);
91            };
92            vector::push_back(&mut game.grid, row);
93        };
94    }
95
96    public entry fun stop_game(caller: &signer) acquires ModuleData {
97        let module_data = borrow_global_mut<ModuleData>(@martian);
98        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
99        assert!(table::contains<address, Game>(&module_data.games, signer::address_of(caller)), error::permission_denied(EGAME_NOT_STARTED));
100        table::remove(&mut module_data.games, signer::address_of(caller));
101    }
102
103    public entry fun start_game(caller: &signer, prompt: String) acquires ModuleData{
104        let module_data = borrow_global_mut<ModuleData>(@martian);
105        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
106        if (table::contains<address, Game>(&module_data.games, signer::address_of(caller))) {
107            let game = table::borrow_mut(&mut module_data.games, signer::address_of(caller));
108            if (game.expiration_timestamp < timestamp::now_seconds()) {
109                table::remove(&mut module_data.games, signer::address_of(caller));
110            };
111        };
112        assert!(!table::contains<address, Game>(&module_data.games, signer::address_of(caller)), error::permission_denied(ECANNOT_START_GAME));
113        let grid = vector::empty();
114        for (i in 0..6) {
115            let row = vector::empty();
116            for (j in 0..7) {
117                vector::push_back(&mut row, 0);
118            };
119            vector::push_back(&mut grid, row);
120        };
121        table::add(&mut module_data.games, signer::address_of(caller), Game {
122            game_id: module_data.games_count,
123            expiration_timestamp: timestamp::now_seconds() + 6000,
124            player_turn: true,
125            player: signer::address_of(caller),
126            grid: grid,
127            winner_nft_prompt: prompt,
128        });
129        module_data.games_count = module_data.games_count + 1;
130    }
131
132    fun transfer_fee(caller: &signer, fee_account: address, amount: u64) {
133        coin::transfer<AptosCoin>(caller, fee_account, amount);
134    }
135
136    public entry fun request_ai(caller: &signer, type: String, model_id: String, input_params: String) acquires ModuleData{
137        let module_data = borrow_global_mut<ModuleData>(@martian);
138        module_data.request_count = module_data.request_count+1;
139        transfer_fee(caller, module_data.fee_account, module_data.usage_fee);
140        table::add(&mut module_data.active_requests, module_data.request_count, true);
141        request(
142            caller,
143            type,
144            model_id,
145            input_params,
146            @martian,
147            module_data.request_count,
148            string::utf8(b"score4::response_ai"),
149        );
150    }
151
152    fun check_game_over(grid: vector<vector<u8>>): bool {
153        let result = true;
154        for (i in 0..6) {
155            for (j in 0..7) {
156                let row_vector = vector::borrow(&grid, i);
157                let value = vector::borrow(row_vector, j);
158                if (*value == 0) {
159                    result = false;
160                };
161            };
162        };
163
164        result
165    }
166
167    fun check_win_lose(grid: vector<vector<u8>>, flag: u8): bool {
168        let result = false;
169
170        // Check rows
171        for (i in 0..6) {
172            for (j in 0..4) {
173                if (*vector::borrow(vector::borrow(&grid, i), j) == flag &&
174                    *vector::borrow(vector::borrow(&grid, i), j + 1) == flag &&
175                    *vector::borrow(vector::borrow(&grid, i), j + 2) == flag &&
176                    *vector::borrow(vector::borrow(&grid, i), j + 3) == flag) {
177                    result = true;
178                };
179            };
180        };
181
182        // Check columns
183        for (i in 0..3) {
184            for (j in 0..7) {
185                if (*vector::borrow(vector::borrow(&grid, i), j) == flag &&
186                    *vector::borrow(vector::borrow(&grid, i + 1), j) == flag &&
187                    *vector::borrow(vector::borrow(&grid, i + 2), j) == flag &&
188                    *vector::borrow(vector::borrow(&grid, i + 3), j) == flag) {
189                    result = true;
190                };
191            };
192        };
193
194        // Check diagonals (bottom left to top right)
195        for (i in 0..3) {
196            for (j in 0..4) {
197                if (*vector::borrow(vector::borrow(&grid, i), j) == flag &&
198                    *vector::borrow(vector::borrow(&grid, i + 1), j + 1) == flag &&
199                    *vector::borrow(vector::borrow(&grid, i + 2), j + 2) == flag &&
200                    *vector::borrow(vector::borrow(&grid, i + 3), j + 3) == flag) {
201                    result = true;
202                };
203            };
204        };
205
206                // Check diagonals (top left to bottom right)
207        for (i in 0..3) {
208            for (j in 3..7) {
209                if (*vector::borrow(vector::borrow(&grid, i), j) == flag &&
210                    *vector::borrow(vector::borrow(&grid, i + 1), j - 1) == flag &&
211                    *vector::borrow(vector::borrow(&grid, i + 2), j - 2) == flag &&
212                    *vector::borrow(vector::borrow(&grid, i + 3), j - 3) == flag) {
213                    result = true;
214                };
215            };
216        };
217
218        result
219    }
220
221    fun convert_grid_to_string(grid: vector<vector<u8>>): String {
222        let result = string::utf8(b"");
223        for (i in 0..6) {
224            let row_vector = vector::borrow(&grid, i);
225            string::append(&mut result, string::utf8(*row_vector));
226        };
227        result
228    }
229
230    public entry fun play_move(caller: &signer, column: u64) acquires ModuleData {
231        let module_data = borrow_global_mut<ModuleData>(@martian);
232        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
233        assert!(table::contains<address, Game>(&module_data.games, signer::address_of(caller)), error::permission_denied(EGAME_NOT_STARTED));
234        {
235            let game = table::borrow_mut(&mut module_data.games, signer::address_of(caller));
236            let row = get_empty_row(game.grid, column);
237            assert!(row != 10, error::permission_denied(EMOVE_NOT_ALLOWED));
238            let row_vector = vector::borrow_mut(&mut game.grid, row);
239            let value = vector::borrow_mut(row_vector, column);
240            assert!(game.player == signer::address_of(caller), error::permission_denied(ENOT_AUTHORIZED));
241            assert!(game.expiration_timestamp > timestamp::now_seconds(), error::permission_denied(EGAME_EXPIRED));
242            assert!(game.player_turn == true, error::permission_denied(EMOVE_NOT_ALLOWED));
243            *value = 1;
244            game.player_turn = !game.player_turn;
245            game.expiration_timestamp = timestamp::now_seconds() + 6000;
246        };
247        let game = table::borrow(& module_data.games, signer::address_of(caller));
248        let player = game.player;
249        let grid = game.grid;
250        let game_id = game.game_id;
251        let outcome = string::utf8(b"3");
252        if (check_win_lose(grid, 1)) {
253            outcome = string::utf8(b"1");
254            create_nft::request_ai(caller, string::utf8(b"inference"), module_data.mint_nft_model_address, game.winner_nft_prompt);
255        } else if (check_win_lose(grid, 2)) {
256            outcome = string::utf8(b"2");
257        } else if (check_game_over(grid)) {
258            outcome = string::utf8(b"0");
259        };
260        if (outcome != string::utf8(b"3")) {
261            event::emit(
262                GameEvent {
263                    game_id: game_id,
264                    player: player,
265                    outcome: outcome,
266                }
267            );
268            table::remove(&mut module_data.games, player);
269        } else {
270            request_ai(
271                caller,
272                string::utf8(b"inference"),
273                module_data.model_address,
274                convert_grid_to_string(grid),
275            );
276        }
277    }
278
279    fun get_empty_row(grid: vector<vector<u8>>, column: u64): u64 {
280        let ret = 10;
281        for (i in 0..6) {
282            let row_vector = vector::borrow(&grid, i);
283            let value = vector::borrow(row_vector, column);
284            if (*value == 0) {
285                ret = i;
286            };
287        };
288        ret
289    }
290
291    public entry fun response_ai(caller: &signer, coordinator_request_id: u64, client_request_id: u64, requestor_address: address, column: u64) acquires ModuleData {
292        check_admin(caller);
293        
294        let module_data = borrow_global_mut<ModuleData>(@martian);
295        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
296
297        assert!(table::contains<address, Game>(&module_data.games, requestor_address), error::permission_denied(EGAME_NOT_STARTED));
298
299        {
300            let game = table::borrow_mut(&mut module_data.games, requestor_address);
301            let row = get_empty_row(game.grid, column);
302            assert!(row != 10, error::permission_denied(EMOVE_NOT_ALLOWED));
303            let row_vector = vector::borrow_mut(&mut game.grid, row);
304            let value = vector::borrow_mut(row_vector, column);
305            assert!(game.expiration_timestamp > timestamp::now_seconds(), error::permission_denied(EGAME_EXPIRED));
306            assert!(*value == 0, error::permission_denied(EMOVE_NOT_ALLOWED));
307            assert!(game.player_turn == false, error::permission_denied(EMOVE_NOT_ALLOWED));
308            *value = 2;
309            game.player_turn = !game.player_turn;
310            game.expiration_timestamp = timestamp::now_seconds() + 6000;
311        };
312        let game = table::borrow(& module_data.games, requestor_address);
313        let player = game.player;
314        let grid = game.grid;
315        let game_id = game.game_id;
316        let outcome = string::utf8(b"3");
317        if (check_win_lose(grid, 1)) {
318            outcome = string::utf8(b"1");
319        };
320        if (check_win_lose(grid, 2)) {
321            outcome = string::utf8(b"2");
322        };
323        if (check_game_over(grid)) {
324            outcome = string::utf8(b"0");
325        };
326        if (outcome != string::utf8(b"3")) {
327            event::emit(
328                GameEvent {
329                    game_id: game_id,
330                    player: player,
331                    outcome: outcome,
332                }
333            );
334            table::remove(&mut module_data.games, player);
335        };
336        table::remove(&mut module_data.active_requests, client_request_id);
337        coordinator::response(caller, coordinator_request_id, requestor_address, outcome);
338        transfer_fee(caller, @coordinator, 100);
339    }
340
341    #[view]
342    public fun get_grid(player: address): String acquires ModuleData {
343        let module_data = borrow_global<ModuleData>(@martian);
344        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
345        assert!(table::contains<address, Game>(&module_data.games, player), error::permission_denied(EGAME_NOT_STARTED));
346        let game = table::borrow(&module_data.games, player);
347        convert_grid_to_string(game.grid)
348    }
349
350    #[view]
351    public fun get_game(player: address): u64 acquires ModuleData {
352        let module_data = borrow_global<ModuleData>(@martian);
353        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
354        assert!(table::contains<address, Game>(&module_data.games, player), error::permission_denied(EGAME_NOT_STARTED));
355        table::borrow(&module_data.games, player).game_id
356    }
357
358    #[view]
359    public fun get_player_turn(player: address): bool acquires ModuleData {
360        let module_data = borrow_global<ModuleData>(@martian);
361        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
362        assert!(table::contains<address, Game>(&module_data.games, player), error::permission_denied(EGAME_NOT_STARTED));
363        table::borrow(&module_data.games, player).player_turn
364    }
365
366    #[view]
367    public fun get_game_expiration(player: address): u64 acquires ModuleData {
368        let module_data = borrow_global<ModuleData>(@martian);
369        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
370        assert!(table::contains<address, Game>(&module_data.games, player), error::permission_denied(EGAME_NOT_STARTED));
371        table::borrow(&module_data.games, player).expiration_timestamp
372    }
373
374    #[view]
375    public fun get_game_count(): u64 acquires ModuleData {
376        let module_data = borrow_global<ModuleData>(@martian);
377        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
378        module_data.games_count
379    }
380
381    #[view]
382    public fun get_request_count(): u64 acquires ModuleData {
383        let module_data = borrow_global<ModuleData>(@martian);
384        assert!(module_data.module_enabled, error::permission_denied(EMODULE_DISABLED));
385        module_data.request_count
386    }
387
388    public entry fun set_module_enabled(caller: &signer, module_enabled: bool) acquires ModuleData {
389        // Abort if the caller is not the admin of this module.
390        check_admin(caller);
391        let module_data = borrow_global_mut<ModuleData>(@martian);
392        module_data.module_enabled = module_enabled;
393    }
394
395    public entry fun change_model_address(caller: &signer, model_address: String) acquires ModuleData {
396        // Abort if the caller is not the admin of this module.
397        check_admin(caller);
398        let module_data = borrow_global_mut<ModuleData>(@martian);
399        module_data.model_address = model_address;
400    }
401
402    public entry fun set_fee_details(caller: &signer, usage_fee: u64, fee_account: address) acquires ModuleData {
403        // Abort if the caller is not the admin of this module.
404        check_admin(caller);
405        let module_data = borrow_global_mut<ModuleData>(@martian);
406        module_data.usage_fee = usage_fee;
407        module_data.fee_account = fee_account;
408    }
409
410    public entry fun add_admin(caller: &signer, admin: address) acquires ModuleData {
411        // Abort if the caller is not the admin of this module.
412        check_admin(caller);
413        let module_data = borrow_global_mut<ModuleData>(@martian);
414        if (!vector::contains(&module_data.admin_addresses, &admin)) {
415            vector::push_back(&mut module_data.admin_addresses, admin);
416        }
417    }
418
419    public entry fun remove_admin(caller: &signer, admin: address) acquires ModuleData {
420        // Abort if the caller is not the admin of this module.
421        check_admin(caller);
422        let module_data = borrow_global_mut<ModuleData>(@martian);
423        vector::remove_value(&mut module_data.admin_addresses, &admin);
424    }
425}

ABI

{
address:
"0x6fe167c9ea99f6ed855311d7d6aafa6be87ee2e0b5218f0d57633b5f24c2c4c1"
name:
"score4"
friends:[
]
exposed_functions:[
0:{
name:
"add_admin"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"address"
]
return:[
]
}
1:{
name:
"change_model_address"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"0x1::string::String"
]
return:[
]
}
2:{
name:
"get_game"
visibility:
"public"
is_entry:
false
is_view:
true
generic_type_params:[
]
params:[
0
:
"address"
]
return:[
0
:
"u64"
]
}
3:{
name:
"get_game_count"
visibility:
"public"
is_entry:
false
is_view:
true
generic_type_params:[
]
params:[
]
return:[
0
:
"u64"
]
}
4:{
name:
"get_game_expiration"
visibility:
"public"
is_entry:
false
is_view:
true
generic_type_params:[
]
params:[
0
:
"address"
]
return:[
0
:
"u64"
]
}
5:{
name:
"get_grid"
visibility:
"public"
is_entry:
false
is_view:
true
generic_type_params:[
]
params:[
0
:
"address"
]
return:[
0
:
"0x1::string::String"
]
}
6:{
name:
"get_player_turn"
visibility:
"public"
is_entry:
false
is_view:
true
generic_type_params:[
]
params:[
0
:
"address"
]
return:[
0
:
"bool"
]
}
7:{
name:
"get_request_count"
visibility:
"public"
is_entry:
false
is_view:
true
generic_type_params:[
]
params:[
]
return:[
0
:
"u64"
]
}
8:{
name:
"play_move"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"u64"
]
return:[
]
}
9:{
name:
"remove_admin"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"address"
]
return:[
]
}
10:{
name:
"request_ai"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"0x1::string::String"
2
:
"0x1::string::String"
3
:
"0x1::string::String"
]
return:[
]
}
11:{
name:
"response_ai"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"u64"
2
:
"u64"
3
:
"address"
4
:
"u64"
]
return:[
]
}
12:{
name:
"restart_game"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
]
return:[
]
}
13:{
name:
"set_fee_details"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"u64"
2
:
"address"
]
return:[
]
}
14:{
name:
"set_module_enabled"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"bool"
]
return:[
]
}
15:{
name:
"start_game"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
1
:
"0x1::string::String"
]
return:[
]
}
16:{
name:
"stop_game"
visibility:
"public"
is_entry:
true
is_view:
false
generic_type_params:[
]
params:[
0
:
"&signer"
]
return:[
]
}
]
structs:[
0:{
name:
"Game"
is_native:
false
is_event:
false
abilities:[
0
:
"drop"
1
:
"store"
2
:
"key"
]
generic_type_params:[
]
fields:[
0:{
name:
"game_id"
type:
"u64"
}
1:{
name:
"expiration_timestamp"
type:
"u64"
}
2:{
name:
"player_turn"
type:
"bool"
}
3:{
name:
"player"
type:
"address"
}
4:{
name:
"grid"
type:
"vector<vector<u8>>"
}
5:{
name:
"winner_nft_prompt"
type:
"0x1::string::String"
}
]
}
1:{
name:
"GameEvent"
is_native:
false
is_event:
true
abilities:[
0
:
"drop"
1
:
"store"
]
generic_type_params:[
]
fields:[
0:{
name:
"game_id"
type:
"u64"
}
1:{
name:
"player"
type:
"address"
}
2:{
name:
"outcome"
type:
"0x1::string::String"
}
]
}
2:{
name:
"ModuleData"
is_native:
false
is_event:
false
abilities:[
0
:
"key"
]
generic_type_params:[
]
fields:[
0:{
name:
"signer_cap"
type:
"0x1::account::SignerCapability"
}
1:{
name:
"module_enabled"
type:
"bool"
}
2:{
name:
"games_count"
type:
"u64"
}
3:{
name:
"request_count"
type:
"u64"
}
4:{
name:
"games"
type:
"0x1::table::Table<address, 0x6fe167c9ea99f6ed855311d7d6aafa6be87ee2e0b5218f0d576 ..."
}
5:{
name:
"active_requests"
type:
"0x1::table::Table<u64, bool>"
}
6:{
name:
"model_address"
type:
"0x1::string::String"
}
7:{
name:
"usage_fee"
type:
"u64"
}
8:{
name:
"fee_account"
type:
"address"
}
9:{
name:
"admin_addresses"
type:
"vector<address>"
}
10:{
name:
"mint_nft_model_address"
type:
"0x1::string::String"
}
]
}
]
}

© 2025 Aptos Labs