prthm11 commited on
Commit
066dd21
·
verified ·
1 Parent(s): 8551593

Delete utils/block_builder_main.py

Browse files
Files changed (1) hide show
  1. utils/block_builder_main.py +0 -446
utils/block_builder_main.py DELETED
@@ -1,446 +0,0 @@
1
- import json
2
- import copy
3
- import re
4
- from collections import defaultdict
5
- import secrets
6
- import string
7
- from typing import Dict, Any, TypedDict
8
- from plan_generator_10 import generate_plan,generate_blocks_from_opcodes,all_block_definitions
9
-
10
- #################################################################################################################################################################
11
- #--------------------------------------------------[Security key id generation for the better understanding of keys]---------------------------------------------
12
- #################################################################################################################################################################
13
-
14
- def generate_secure_token(length=20):
15
- charset = string.ascii_letters + string.digits + "!@#$%^&*()[]{}=+-_~"
16
- return ''.join(secrets.choice(charset) for _ in range(length))
17
-
18
- #################################################################################################################################################################
19
- #--------------------------------------------------[Processed the two Skelton as input and generate refined skelton json]----------------------------------------
20
- #################################################################################################################################################################
21
-
22
- def process_scratch_blocks(all_generated_blocks, generated_output_json):
23
-
24
- processed_blocks = {}
25
-
26
- # Initialize dictionaries to store and reuse generated unique IDs
27
- # This prevents creating multiple unique IDs for the same variable/broadcast across different blocks
28
- variable_id_map = defaultdict(lambda: generate_secure_token(20))
29
- broadcast_id_map = defaultdict(lambda: generate_secure_token(20))
30
-
31
- for block_id, gen_block_data in generated_output_json.items():
32
- processed_block = {}
33
- all_gen_block_data = all_generated_blocks.get(block_id, {})
34
-
35
- # Copy and update fields, inputs, next, parent, shadow, topLevel, mutation, and opcode
36
- processed_block["opcode"] = all_gen_block_data.get("op_code", gen_block_data.get("op_code"))
37
- processed_block["inputs"] = {}
38
- processed_block["fields"] = {}
39
- processed_block["shadow"] = all_gen_block_data.get("shadow", gen_block_data.get("shadow"))
40
- processed_block["topLevel"] = all_gen_block_data.get("topLevel", gen_block_data.get("topLevel"))
41
- processed_block["parent"] = all_gen_block_data.get("parent", gen_block_data.get("parent"))
42
- processed_block["next"] = all_gen_block_data.get("next", gen_block_data.get("next"))
43
- if "mutation" in all_gen_block_data:
44
- processed_block["mutation"] = all_gen_block_data["mutation"]
45
-
46
- # Process inputs
47
- if "inputs" in all_gen_block_data:
48
- for input_name, input_data in all_gen_block_data["inputs"].items():
49
- if input_name in ["SUBSTACK", "CONDITION"]:
50
- # These should always be type 2
51
- if isinstance(input_data, list) and len(input_data) == 2:
52
- processed_block["inputs"][input_name] = [2, input_data[1]]
53
- elif isinstance(input_data, dict) and input_data.get("kind") == "block":
54
- processed_block["inputs"][input_name] = [2, input_data.get("block")]
55
- else: # Fallback for unexpected formats, try to use the original if possible
56
- processed_block["inputs"][input_name] = gen_block_data["inputs"].get(input_name, [2, None])
57
-
58
- elif isinstance(input_data, dict):
59
- if input_data.get("kind") == "value":
60
- # Case 1: Direct value input
61
- processed_block["inputs"][input_name] = [
62
- 1,
63
- [
64
- 4,
65
- str(input_data.get("value", ""))
66
- ]
67
- ]
68
- elif input_data.get("kind") == "block":
69
- # Case 3: Nested block input
70
- existing_shadow_value = ""
71
- if input_name in gen_block_data.get("inputs", {}) and \
72
- isinstance(gen_block_data["inputs"][input_name], list) and \
73
- len(gen_block_data["inputs"][input_name]) > 2 and \
74
- isinstance(gen_block_data["inputs"][input_name][2], list) and \
75
- len(gen_block_data["inputs"][input_name][2]) > 1:
76
- existing_shadow_value = gen_block_data["inputs"][input_name][2][1]
77
-
78
- processed_block["inputs"][input_name] = [
79
- 3,
80
- input_data.get("block", ""),
81
- [
82
- 10, # Assuming 10 for number/string shadow
83
- existing_shadow_value
84
- ]
85
- ]
86
- elif input_data.get("kind") == "menu":
87
- # Handle menu inputs like in event_broadcast
88
- menu_option = input_data.get("option", "")
89
-
90
- # Generate or retrieve a unique ID for the broadcast message
91
- broadcast_id = broadcast_id_map[menu_option] # Use defaultdict for unique IDs
92
-
93
- processed_block["inputs"][input_name] = [
94
- 1,
95
- [
96
- 11, # This is typically the code for menu dropdowns
97
- menu_option,
98
- broadcast_id
99
- ]
100
- ]
101
- elif isinstance(input_data, list):
102
- # For cases like TOUCHINGOBJECTMENU, where input_data is a list [1, "block_id"]
103
- processed_block["inputs"][input_name] = input_data
104
-
105
-
106
- # Process fields
107
- if "fields" in all_gen_block_data:
108
- for field_name, field_value in all_gen_block_data["fields"].items():
109
- if field_name == "VARIABLE" and isinstance(field_value, list) and len(field_value) > 0:
110
- # Generate or retrieve a unique ID for the variable
111
- variable_name = field_value[0]
112
- unique_id = variable_id_map[variable_name] # Use defaultdict for unique IDs
113
-
114
- processed_block["fields"][field_name] = [
115
- variable_name,
116
- unique_id
117
- ]
118
- elif field_name == "STOP_OPTION":
119
- processed_block["fields"][field_name] = [
120
- field_value[0],
121
- None
122
- ]
123
- elif field_name == "TOUCHINGOBJECTMENU":
124
- referenced_menu_block_id = all_gen_block_data["inputs"].get("TOUCHINGOBJECTMENU", [None, None])[1]
125
- if referenced_menu_block_id and referenced_menu_block_id in all_generated_blocks:
126
- menu_block = all_generated_blocks[referenced_menu_block_id]
127
- menu_value = menu_block.get("fields", {}).get("TOUCHINGOBJECTMENU", ["", None])[0]
128
- processed_block["fields"][field_name] = [menu_value, None]
129
- else:
130
- processed_block["fields"][field_name] = [field_value[0], None]
131
- else:
132
- processed_block["fields"][field_name] = field_value
133
-
134
- # Remove unwanted keys from the processed block
135
- keys_to_remove = ["functionality", "block_shape", "id", "block_name", "block_type"]
136
- for key in keys_to_remove:
137
- if key in processed_block:
138
- del processed_block[key]
139
-
140
- processed_blocks[block_id] = processed_block
141
- return processed_blocks
142
- #################################################################################################################################################################
143
- #--------------------------------------------------[Unique secret key for skelton json to make sure it donot overwrite each other]-------------------------------
144
- #################################################################################################################################################################
145
-
146
- def rename_blocks(block_json: dict, opcode_count: dict) -> tuple[dict, dict]:
147
- """
148
- Replace each block key in block_json and each identifier in opcode_count
149
- with a newly generated secure token.
150
-
151
- Args:
152
- block_json: Mapping of block_key -> block_data.
153
- opcode_count: Mapping of opcode -> list of block_keys.
154
-
155
- Returns:
156
- A tuple of (new_block_json, new_opcode_count) with updated keys.
157
- """
158
- # Step 1: Generate a secure token mapping for every existing block key
159
- token_map = {}
160
- for old_key in block_json.keys():
161
- # Ensure uniqueness in the unlikely event of a collision
162
- while True:
163
- new_key = generate_secure_token()
164
- if new_key not in token_map.values():
165
- break
166
- token_map[old_key] = new_key
167
-
168
- # Step 2: Rebuild block_json with new keys
169
- new_block_json = {}
170
- for old_key, block in block_json.items():
171
- new_key = token_map[old_key]
172
- new_block_json[new_key] = block.copy()
173
-
174
- # Update parent and next references
175
- if 'parent' in block and block['parent'] in token_map:
176
- new_block_json[new_key]['parent'] = token_map[block['parent']]
177
- if 'next' in block and block['next'] in token_map:
178
- new_block_json[new_key]['next'] = token_map[block['next']]
179
-
180
- # Update inputs if they reference blocks
181
- for inp_key, inp_val in block.get('inputs', {}).items():
182
- if isinstance(inp_val, list) and len(inp_val) == 2:
183
- idx, ref = inp_val
184
- if idx in (2, 3) and isinstance(ref, str) and ref in token_map:
185
- new_block_json[new_key]['inputs'][inp_key] = [idx, token_map[ref]]
186
-
187
- # Step 3: Update opcode count map
188
- new_opcode_count = {}
189
- for opcode, key_list in opcode_count.items():
190
- new_opcode_count[opcode] = [token_map.get(k, k) for k in key_list]
191
-
192
- return new_block_json, new_opcode_count
193
-
194
- #################################################################################################################################################################
195
- #--------------------------------------------------[Helper function to add Variables and Broadcasts [USed in main app file for main projectjson]]----------------
196
- #################################################################################################################################################################
197
-
198
- def variable_intialization(project_data):
199
- """
200
- Updates variable and broadcast definitions in a Scratch project JSON,
201
- populating the 'variables' and 'broadcasts' sections of the Stage target
202
- and extracting initial values for variables.
203
-
204
- Args:
205
- project_data (dict): The loaded JSON data of the Scratch project.
206
-
207
- Returns:
208
- dict: The updated project JSON data.
209
- """
210
-
211
- stage_target = None
212
- for target in project_data['targets']:
213
- if target.get('isStage'):
214
- stage_target = target
215
- break
216
-
217
- if stage_target is None:
218
- print("Error: Stage target not found in the project data.")
219
- return project_data
220
-
221
- # Ensure 'variables' and 'broadcasts' exist in the Stage target
222
- if "variables" not in stage_target:
223
- stage_target["variables"] = {}
224
- if "broadcasts" not in stage_target:
225
- stage_target["broadcasts"] = {}
226
-
227
- # Helper function to recursively find and update variable/broadcast fields
228
- def process_dict(obj):
229
- if isinstance(obj, dict):
230
- # Check for "data_setvariableto" opcode to extract initial values
231
- if obj.get("opcode") == "data_setvariableto":
232
- variable_field = obj.get("fields", {}).get("VARIABLE")
233
- value_input = obj.get("inputs", {}).get("VALUE")
234
-
235
- if variable_field and isinstance(variable_field, list) and len(variable_field) == 2:
236
- var_name = variable_field[0]
237
- var_id = variable_field[1]
238
-
239
- initial_value = ""
240
- if value_input and isinstance(value_input, list) and len(value_input) > 1 and \
241
- isinstance(value_input[1], list) and len(value_input[1]) > 1:
242
- # Extract value from various formats, e.g., [1, [10, "0"]] or [3, [12, "score", "id"], [10, "0"]]
243
- if value_input[1][0] == 10: # Direct value like [10, "0"]
244
- initial_value = str(value_input[1][1])
245
- elif value_input[1][0] == 12 and len(value_input) > 2 and isinstance(value_input[2], list) and value_input[2][0] == 10: # Variable reference with initial value block
246
- initial_value = str(value_input[2][1])
247
- elif isinstance(value_input[1], (str, int, float)): # For direct number/string inputs
248
- initial_value = str(value_input[1])
249
-
250
-
251
- # Add/update the variable in the Stage's 'variables' with its initial value
252
- stage_target["variables"][var_id] = [var_name, initial_value]
253
-
254
-
255
- for key, value in obj.items():
256
- # Process variable definitions in 'fields' (for blocks that define variables like 'show variable')
257
- if key == "VARIABLE" and isinstance(value, list) and len(value) == 2:
258
- var_name = value[0]
259
- var_id = value[1]
260
- # Only add if not already defined with an initial value from set_variableto
261
- if var_id not in stage_target["variables"]:
262
- stage_target["variables"][var_id] = [var_name, ""] # Default to empty string if no initial value found yet
263
- elif stage_target["variables"][var_id][0] != var_name: # Update name if ID exists but name is different
264
- stage_target["variables"][var_id][0] = var_name
265
-
266
-
267
- # Process broadcast definitions in 'inputs' (BROADCAST_INPUT)
268
- elif key == "BROADCAST_INPUT" and isinstance(value, list) and len(value) == 2 and \
269
- isinstance(value[1], list) and len(value[1]) == 3 and value[1][0] == 11:
270
- broadcast_name = value[1][1]
271
- broadcast_id = value[1][2]
272
- # Add/update the broadcast in the Stage's 'broadcasts'
273
- stage_target["broadcasts"][broadcast_id] = broadcast_name
274
-
275
- # Process broadcast definitions in 'fields' (BROADCAST_OPTION)
276
- elif key == "BROADCAST_OPTION" and isinstance(value, list) and len(value) == 2:
277
- broadcast_name = value[0]
278
- broadcast_id = value[1]
279
- # Add/update the broadcast in the Stage's 'broadcasts'
280
- stage_target["broadcasts"][broadcast_id] = broadcast_name
281
-
282
- # Recursively call for nested dictionaries or lists
283
- process_dict(value)
284
- elif isinstance(obj, list):
285
- for i, item in enumerate(obj):
286
- # Process variable references in 'inputs' (like [12, "score", "id"])
287
- if isinstance(item, list) and len(item) == 3 and item[0] == 12:
288
- var_name = item[1]
289
- var_id = item[2]
290
- # Only add if not already defined with an initial value from set_variableto
291
- if var_id not in stage_target["variables"]:
292
- stage_target["variables"][var_id] = [var_name, ""] # Default to empty string if no initial value found yet
293
- elif stage_target["variables"][var_id][0] != var_name: # Update name if ID exists but name is different
294
- stage_target["variables"][var_id][0] = var_name
295
-
296
- process_dict(item)
297
-
298
- # Iterate through all targets to process their blocks
299
- for target in project_data['targets']:
300
- if "blocks" in target:
301
- for block_id, block_data in target["blocks"].items():
302
- process_dict(block_data)
303
-
304
- return project_data
305
-
306
- def deduplicate_variables(project_data):
307
- """
308
- Removes duplicate variable entries in the 'variables' dictionary of the Stage target,
309
- prioritizing entries with non-empty values.
310
-
311
- Args:
312
- project_data (dict): The loaded JSON data of the Scratch project.
313
-
314
- Returns:
315
- dict: The updated project JSON data with deduplicated variables.
316
- """
317
-
318
- stage_target = None
319
- for target in project_data['targets']:
320
- if target.get('isStage'):
321
- stage_target = target
322
- break
323
-
324
- if stage_target is None:
325
- print("Error: Stage target not found in the project data.")
326
- return project_data
327
-
328
- if "variables" not in stage_target:
329
- return project_data # No variables to deduplicate
330
-
331
- # Use a temporary dictionary to store the preferred variable entry by name
332
- # Format: {variable_name: [variable_id, variable_name, variable_value]}
333
- resolved_variables = {}
334
-
335
- for var_id, var_info in stage_target["variables"].items():
336
- var_name = var_info[0]
337
- var_value = var_info[1]
338
-
339
- if var_name not in resolved_variables:
340
- # If the variable name is not yet seen, add it
341
- resolved_variables[var_name] = [var_id, var_name, var_value]
342
- else:
343
- # If the variable name is already seen, decide which one to keep
344
- existing_id, existing_name, existing_value = resolved_variables[var_name]
345
-
346
- # Prioritize the entry with a non-empty value
347
- if var_value != "" and existing_value == "":
348
- resolved_variables[var_name] = [var_id, var_name, var_value]
349
- # If both have non-empty values, or both are empty, keep the current one (arbitrary choice, but consistent)
350
- # The current logic will effectively keep the last one encountered that has a value,
351
- # or the very last one if all are empty.
352
- elif var_value != "" and existing_value != "":
353
- # If there are multiple non-empty values for the same variable name
354
- # this keeps the one from the most recent iteration.
355
- # For the given example, this will correctly keep "5".
356
- resolved_variables[var_name] = [var_id, var_name, var_value]
357
- elif var_value == "" and existing_value == "":
358
- # If both are empty, just keep the current one (arbitrary)
359
- resolved_variables[var_name] = [var_id, var_name, var_value]
360
-
361
-
362
- # Reconstruct the 'variables' dictionary using the resolved entries
363
- new_variables_dict = {}
364
- for var_name, var_data in resolved_variables.items():
365
- var_id_to_keep = var_data[0]
366
- var_name_to_keep = var_data[1]
367
- var_value_to_keep = var_data[2]
368
- new_variables_dict[var_id_to_keep] = [var_name_to_keep, var_value_to_keep]
369
-
370
- stage_target["variables"] = new_variables_dict
371
-
372
- return project_data
373
-
374
- def variable_adder_main(project_data):
375
- try:
376
- declare_variable_json= variable_intialization(project_data)
377
- except Exception as e:
378
- print(f"Error error in the variable initialization opcodes: {e}")
379
- try:
380
- processed_json= deduplicate_variables(declare_variable_json)
381
- return
382
- except Exception as e:
383
- print(f"Error error in the variable initialization opcodes: {e}")
384
-
385
- #################################################################################################################################################################
386
- #--------------------------------------------------[Helper main function]----------------------------------------------------------------------------------------
387
- #################################################################################################################################################################
388
-
389
- def block_builder(opcode_count,pseudo_code):
390
- try:
391
- generated_output_json, initial_opcode_occurrences = generate_blocks_from_opcodes(opcode_count, all_block_definitions)
392
- except Exception as e:
393
- print(f"Error generating blocks from opcodes: {e}")
394
- return {}
395
- try:
396
- all_generated_blocks = generate_plan(generated_output_json, initial_opcode_occurrences, pseudo_code)
397
- except Exception as e:
398
- print(f"Error generating plan from blocks: {e}")
399
- return {}
400
- try:
401
- processed_blocks= process_scratch_blocks(all_generated_blocks, generated_output_json)
402
- except Exception as e:
403
- print(f"Error processing Scratch blocks: {e}")
404
- return {}
405
- renamed_blocks, renamed_counts = rename_blocks(processed_blocks, initial_opcode_occurrences)
406
- return renamed_blocks
407
-
408
- #################################################################################################################################################################
409
- #--------------------------------------------------[Example use of the function here]----------------------------------------------------------------------------
410
- #################################################################################################################################################################
411
-
412
- initial_opcode_counts = [
413
- {
414
- "opcode": "event_whenflagclicked",
415
- "count": 1
416
- },
417
- {
418
- "opcode": "data_setvariableto",
419
- "count": 2
420
- },
421
- {
422
- "opcode": "data_showvariable",
423
- "count": 2
424
- },
425
- {
426
- "opcode": "event_broadcast",
427
- "count": 1
428
- }
429
- ]
430
- pseudo_code="""
431
- when green flag clicked
432
- set [score v] to (0)
433
- set [lives v] to (3)
434
- show variable [score v]
435
- show variable [lives v]
436
- broadcast [Game Start v]
437
- """
438
-
439
- generated_output_json, initial_opcode_occurrences = generate_blocks_from_opcodes(initial_opcode_counts, all_block_definitions)
440
- all_generated_blocks = generate_plan(generated_output_json, initial_opcode_occurrences, pseudo_code)
441
- processed_blocks= process_scratch_blocks(all_generated_blocks, generated_output_json)
442
- print(all_generated_blocks)
443
- print("--------------\n\n")
444
- print(processed_blocks)
445
- print("--------------\n\n")
446
- print(initial_opcode_occurrences)