Spaces:
Running
Running
Update utils/block_relation_builder.py
Browse files- utils/block_relation_builder.py +93 -49
utils/block_relation_builder.py
CHANGED
|
@@ -4,7 +4,7 @@ import re
|
|
| 4 |
from collections import defaultdict
|
| 5 |
import secrets
|
| 6 |
import string
|
| 7 |
-
from typing import Dict, Any, TypedDict
|
| 8 |
|
| 9 |
|
| 10 |
#################################################################################################################################################################
|
|
@@ -1871,7 +1871,8 @@ def classify(line):
|
|
| 1871 |
if l.startswith("if <"): return "control_if", "c_block"
|
| 1872 |
if l.startswith("repeat until <"): return "control_repeat_until", "c_block"
|
| 1873 |
# Updated regex for stop block to handle different options
|
| 1874 |
-
if re.match(r"stop \[(all|this script|other scripts in sprite)\s*v\]", l): return "control_stop", "cap"
|
|
|
|
| 1875 |
if l.startswith("create clone of"): return "control_create_clone_of", "stack"
|
| 1876 |
if l == "delete this clone": return "control_delete_this_clone", "cap"
|
| 1877 |
|
|
@@ -2572,8 +2573,9 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
|
|
| 2572 |
for input_name, input_data in all_gen_block_data["inputs"].items():
|
| 2573 |
if input_name == "BROADCAST_INPUT":
|
| 2574 |
# Special handling for BROADCAST_INPUT (type 11)
|
| 2575 |
-
if isinstance(input_data, dict) and input_data.get("kind") == "
|
| 2576 |
-
|
|
|
|
| 2577 |
broadcast_id = broadcast_id_map[menu_option]
|
| 2578 |
processed_block["inputs"][input_name] = [
|
| 2579 |
1,
|
|
@@ -2794,12 +2796,66 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
|
|
| 2794 |
|
| 2795 |
processed_blocks[block_id] = processed_block
|
| 2796 |
return processed_blocks
|
| 2797 |
-
|
| 2798 |
#################################################################################################################################################################
|
| 2799 |
#--------------------------------------------------[Unique secret key for skelton json to make sure it donot overwrite each other]-------------------------------
|
| 2800 |
#################################################################################################################################################################
|
| 2801 |
|
| 2802 |
-
def rename_blocks(block_json:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2803 |
"""
|
| 2804 |
Replace each block key in block_json and each identifier in opcode_count
|
| 2805 |
with a newly generated secure token.
|
|
@@ -2895,60 +2951,39 @@ def variable_intialization(project_data):
|
|
| 2895 |
initial_value = ""
|
| 2896 |
if value_input and isinstance(value_input, list) and len(value_input) > 1 and \
|
| 2897 |
isinstance(value_input[1], list) and len(value_input[1]) > 1:
|
| 2898 |
-
|
| 2899 |
-
if value_input[1][0] == 10: # Direct value like [10, "0"]
|
| 2900 |
initial_value = str(value_input[1][1])
|
| 2901 |
-
elif value_input[1][0] == 12 and len(value_input) > 2 and isinstance(value_input[2], list) and value_input[2][0] == 10:
|
| 2902 |
-
|
| 2903 |
-
elif isinstance(value_input[1], (str, int, float)):
|
| 2904 |
initial_value = str(value_input[1])
|
| 2905 |
-
|
| 2906 |
-
|
| 2907 |
-
# Add/update the variable in the Stage's 'variables' with its initial value
|
| 2908 |
stage_target["variables"][var_id] = [var_name, initial_value]
|
| 2909 |
|
| 2910 |
-
|
| 2911 |
for key, value in obj.items():
|
| 2912 |
-
# Process variable definitions in 'fields' (for blocks that define variables like 'show variable')
|
| 2913 |
-
if key == "VARIABLE" and isinstance(value, list) and len(value) == 2:
|
| 2914 |
-
var_name = value[0]
|
| 2915 |
-
var_id = value[1]
|
| 2916 |
-
# Only add if not already defined with an initial value from set_variableto
|
| 2917 |
-
if var_id not in stage_target["variables"]:
|
| 2918 |
-
stage_target["variables"][var_id] = [var_name, ""] # Default to empty string if no initial value found yet
|
| 2919 |
-
elif stage_target["variables"][var_id][0] != var_name: # Update name if ID exists but name is different
|
| 2920 |
-
stage_target["variables"][var_id][0] = var_name
|
| 2921 |
-
|
| 2922 |
-
|
| 2923 |
# Process broadcast definitions in 'inputs' (BROADCAST_INPUT)
|
| 2924 |
-
|
| 2925 |
-
|
| 2926 |
broadcast_name = value[1][1]
|
| 2927 |
broadcast_id = value[1][2]
|
| 2928 |
-
# Add/update the broadcast in the Stage's 'broadcasts'
|
| 2929 |
stage_target["broadcasts"][broadcast_id] = broadcast_name
|
| 2930 |
|
| 2931 |
# Process broadcast definitions in 'fields' (BROADCAST_OPTION)
|
| 2932 |
elif key == "BROADCAST_OPTION" and isinstance(value, list) and len(value) == 2:
|
| 2933 |
broadcast_name = value[0]
|
| 2934 |
broadcast_id = value[1]
|
| 2935 |
-
# Add/update the broadcast in the Stage's 'broadcasts'
|
| 2936 |
stage_target["broadcasts"][broadcast_id] = broadcast_name
|
| 2937 |
-
|
| 2938 |
# Recursively call for nested dictionaries or lists
|
| 2939 |
process_dict(value)
|
|
|
|
| 2940 |
elif isinstance(obj, list):
|
| 2941 |
for i, item in enumerate(obj):
|
| 2942 |
# Process variable references in 'inputs' (like [12, "score", "id"])
|
| 2943 |
if isinstance(item, list) and len(item) == 3 and item[0] == 12:
|
| 2944 |
var_name = item[1]
|
| 2945 |
var_id = item[2]
|
| 2946 |
-
# Only add if not already defined with an initial value from set_variableto
|
| 2947 |
if var_id not in stage_target["variables"]:
|
| 2948 |
-
stage_target["variables"][var_id] = [var_name, ""]
|
| 2949 |
-
elif stage_target["variables"][var_id][0] != var_name: # Update name if ID exists but name is different
|
| 2950 |
-
stage_target["variables"][var_id][0] = var_name
|
| 2951 |
-
|
| 2952 |
process_dict(item)
|
| 2953 |
|
| 2954 |
# Iterate through all targets to process their blocks
|
|
@@ -3030,14 +3065,15 @@ def deduplicate_variables(project_data):
|
|
| 3030 |
def variable_adder_main(project_data):
|
| 3031 |
try:
|
| 3032 |
declare_variable_json= variable_intialization(project_data)
|
|
|
|
| 3033 |
except Exception as e:
|
| 3034 |
print(f"Error error in the variable initialization opcodes: {e}")
|
| 3035 |
try:
|
| 3036 |
processed_json= deduplicate_variables(declare_variable_json)
|
| 3037 |
-
|
|
|
|
| 3038 |
except Exception as e:
|
| 3039 |
print(f"Error error in the variable initialization opcodes: {e}")
|
| 3040 |
-
|
| 3041 |
#################################################################################################################################################################
|
| 3042 |
#--------------------------------------------------[Helper main function]----------------------------------------------------------------------------------------
|
| 3043 |
#################################################################################################################################################################
|
|
@@ -3066,18 +3102,24 @@ def block_builder(opcode_count,pseudo_code):
|
|
| 3066 |
#################################################################################################################################################################
|
| 3067 |
|
| 3068 |
initial_opcode_counts = [
|
| 3069 |
-
{
|
| 3070 |
-
|
| 3071 |
-
|
| 3072 |
-
},
|
| 3073 |
-
{
|
| 3074 |
-
|
| 3075 |
-
|
| 3076 |
-
}
|
| 3077 |
]
|
| 3078 |
pseudo_code="""
|
| 3079 |
-
when I receive [Game
|
| 3080 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3081 |
end
|
| 3082 |
"""
|
| 3083 |
# print(pseudo_code)
|
|
@@ -3085,8 +3127,10 @@ end
|
|
| 3085 |
# all_generated_blocks = generate_plan(generated_output_json, initial_opcode_occurrences, pseudo_code)
|
| 3086 |
# processed_blocks= process_scratch_blocks(all_generated_blocks, generated_output_json)
|
| 3087 |
# renamed_blocks, renamed_counts = rename_blocks(processed_blocks, initial_opcode_occurrences)
|
| 3088 |
-
# print(all_generated_blocks)
|
| 3089 |
# print("--------------\n\n")
|
| 3090 |
# print(processed_blocks)
|
| 3091 |
# print("--------------\n\n")
|
|
|
|
|
|
|
| 3092 |
# print(renamed_blocks)
|
|
|
|
| 4 |
from collections import defaultdict
|
| 5 |
import secrets
|
| 6 |
import string
|
| 7 |
+
from typing import Dict, Any, TypedDict,Tuple
|
| 8 |
|
| 9 |
|
| 10 |
#################################################################################################################################################################
|
|
|
|
| 1871 |
if l.startswith("if <"): return "control_if", "c_block"
|
| 1872 |
if l.startswith("repeat until <"): return "control_repeat_until", "c_block"
|
| 1873 |
# Updated regex for stop block to handle different options
|
| 1874 |
+
#if re.match(r"stop \[(all|this script|other scripts in sprite)\s*v\]", l): return "control_stop", "cap"
|
| 1875 |
+
if re.match(r"stop\s*(?:[\[(]?\s*(all|this script|other scripts in sprite)\s*[\])]?$)", l, re.IGNORECASE): return "control_stop", "cap"
|
| 1876 |
if l.startswith("create clone of"): return "control_create_clone_of", "stack"
|
| 1877 |
if l == "delete this clone": return "control_delete_this_clone", "cap"
|
| 1878 |
|
|
|
|
| 2573 |
for input_name, input_data in all_gen_block_data["inputs"].items():
|
| 2574 |
if input_name == "BROADCAST_INPUT":
|
| 2575 |
# Special handling for BROADCAST_INPUT (type 11)
|
| 2576 |
+
if isinstance(input_data, dict) and input_data.get("kind") == "value":
|
| 2577 |
+
# This is the new logic to handle a direct value for broadcast
|
| 2578 |
+
menu_option = input_data.get("value", "message1")
|
| 2579 |
broadcast_id = broadcast_id_map[menu_option]
|
| 2580 |
processed_block["inputs"][input_name] = [
|
| 2581 |
1,
|
|
|
|
| 2796 |
|
| 2797 |
processed_blocks[block_id] = processed_block
|
| 2798 |
return processed_blocks
|
| 2799 |
+
|
| 2800 |
#################################################################################################################################################################
|
| 2801 |
#--------------------------------------------------[Unique secret key for skelton json to make sure it donot overwrite each other]-------------------------------
|
| 2802 |
#################################################################################################################################################################
|
| 2803 |
|
| 2804 |
+
def rename_blocks(block_json: Dict[str, Any], opcode_count: Dict[str, list]) -> Tuple[Dict[str, Any], Dict[str, list]]:
|
| 2805 |
+
"""
|
| 2806 |
+
Replace each block key in block_json and each identifier in opcode_count
|
| 2807 |
+
with a newly generated secure token, ensuring all references are updated.
|
| 2808 |
+
|
| 2809 |
+
Args:
|
| 2810 |
+
block_json: Mapping of block_key -> block_data.
|
| 2811 |
+
opcode_count: Mapping of opcode -> list of block_keys.
|
| 2812 |
+
|
| 2813 |
+
Returns:
|
| 2814 |
+
A tuple of (new_block_json, new_opcode_count) with updated keys.
|
| 2815 |
+
"""
|
| 2816 |
+
token_map = {}
|
| 2817 |
+
|
| 2818 |
+
# Step 1: Generate a secure token mapping for every existing block key
|
| 2819 |
+
for old_key in block_json.keys():
|
| 2820 |
+
while True:
|
| 2821 |
+
new_key = generate_secure_token()
|
| 2822 |
+
if new_key not in token_map.values():
|
| 2823 |
+
break
|
| 2824 |
+
token_map[old_key] = new_key
|
| 2825 |
+
|
| 2826 |
+
new_block_json = {}
|
| 2827 |
+
|
| 2828 |
+
# Step 2: Rebuild block_json with new keys and update all references
|
| 2829 |
+
for old_key, block in block_json.items():
|
| 2830 |
+
new_key = token_map[old_key]
|
| 2831 |
+
new_block_json[new_key] = block.copy()
|
| 2832 |
+
|
| 2833 |
+
# Update parent and next references
|
| 2834 |
+
if 'parent' in block and block['parent'] in token_map:
|
| 2835 |
+
new_block_json[new_key]['parent'] = token_map[block['parent']]
|
| 2836 |
+
if 'next' in block and block['next'] in token_map:
|
| 2837 |
+
new_block_json[new_key]['next'] = token_map[block['next']]
|
| 2838 |
+
|
| 2839 |
+
# Update inputs that reference blocks
|
| 2840 |
+
if 'inputs' in block:
|
| 2841 |
+
for inp_key, inp_val in block['inputs'].items():
|
| 2842 |
+
# This handles references like [2, 'block_key']
|
| 2843 |
+
if isinstance(inp_val, list) and len(inp_val) == 2:
|
| 2844 |
+
idx, ref = inp_val
|
| 2845 |
+
if isinstance(ref, str) and ref in token_map:
|
| 2846 |
+
new_block_json[new_key]['inputs'][inp_key] = [idx, token_map[ref]]
|
| 2847 |
+
# This new block handles references like [3, 'block_key', [10, '']]
|
| 2848 |
+
elif isinstance(inp_val, list) and len(inp_val) == 3:
|
| 2849 |
+
idx, ref, rest = inp_val
|
| 2850 |
+
if isinstance(ref, str) and ref in token_map:
|
| 2851 |
+
new_block_json[new_key]['inputs'][inp_key] = [idx, token_map[ref], rest]
|
| 2852 |
+
|
| 2853 |
+
# Step 3: Update opcode count map
|
| 2854 |
+
new_opcode_count = {}
|
| 2855 |
+
for opcode, key_list in opcode_count.items():
|
| 2856 |
+
new_opcode_count[opcode] = [token_map.get(k, k) for k in key_list]
|
| 2857 |
+
|
| 2858 |
+
return new_block_json, new_opcode_count
|
| 2859 |
"""
|
| 2860 |
Replace each block key in block_json and each identifier in opcode_count
|
| 2861 |
with a newly generated secure token.
|
|
|
|
| 2951 |
initial_value = ""
|
| 2952 |
if value_input and isinstance(value_input, list) and len(value_input) > 1 and \
|
| 2953 |
isinstance(value_input[1], list) and len(value_input[1]) > 1:
|
| 2954 |
+
if value_input[1][0] == 10:
|
|
|
|
| 2955 |
initial_value = str(value_input[1][1])
|
| 2956 |
+
elif value_input[1][0] == 12 and len(value_input) > 2 and isinstance(value_input[2], list) and value_input[2][0] == 10:
|
| 2957 |
+
initial_value = str(value_input[2][1])
|
| 2958 |
+
elif isinstance(value_input[1], (str, int, float)):
|
| 2959 |
initial_value = str(value_input[1])
|
|
|
|
|
|
|
|
|
|
| 2960 |
stage_target["variables"][var_id] = [var_name, initial_value]
|
| 2961 |
|
|
|
|
| 2962 |
for key, value in obj.items():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2963 |
# Process broadcast definitions in 'inputs' (BROADCAST_INPUT)
|
| 2964 |
+
if key == "BROADCAST_INPUT" and isinstance(value, list) and len(value) == 2 and \
|
| 2965 |
+
isinstance(value[1], list) and len(value[1]) == 3 and value[1][0] == 11:
|
| 2966 |
broadcast_name = value[1][1]
|
| 2967 |
broadcast_id = value[1][2]
|
|
|
|
| 2968 |
stage_target["broadcasts"][broadcast_id] = broadcast_name
|
| 2969 |
|
| 2970 |
# Process broadcast definitions in 'fields' (BROADCAST_OPTION)
|
| 2971 |
elif key == "BROADCAST_OPTION" and isinstance(value, list) and len(value) == 2:
|
| 2972 |
broadcast_name = value[0]
|
| 2973 |
broadcast_id = value[1]
|
|
|
|
| 2974 |
stage_target["broadcasts"][broadcast_id] = broadcast_name
|
| 2975 |
+
|
| 2976 |
# Recursively call for nested dictionaries or lists
|
| 2977 |
process_dict(value)
|
| 2978 |
+
|
| 2979 |
elif isinstance(obj, list):
|
| 2980 |
for i, item in enumerate(obj):
|
| 2981 |
# Process variable references in 'inputs' (like [12, "score", "id"])
|
| 2982 |
if isinstance(item, list) and len(item) == 3 and item[0] == 12:
|
| 2983 |
var_name = item[1]
|
| 2984 |
var_id = item[2]
|
|
|
|
| 2985 |
if var_id not in stage_target["variables"]:
|
| 2986 |
+
stage_target["variables"][var_id] = [var_name, ""]
|
|
|
|
|
|
|
|
|
|
| 2987 |
process_dict(item)
|
| 2988 |
|
| 2989 |
# Iterate through all targets to process their blocks
|
|
|
|
| 3065 |
def variable_adder_main(project_data):
|
| 3066 |
try:
|
| 3067 |
declare_variable_json= variable_intialization(project_data)
|
| 3068 |
+
print("declare_variable_json------->",declare_variable_json)
|
| 3069 |
except Exception as e:
|
| 3070 |
print(f"Error error in the variable initialization opcodes: {e}")
|
| 3071 |
try:
|
| 3072 |
processed_json= deduplicate_variables(declare_variable_json)
|
| 3073 |
+
print("processed_json------->",processed_json)
|
| 3074 |
+
return processed_json
|
| 3075 |
except Exception as e:
|
| 3076 |
print(f"Error error in the variable initialization opcodes: {e}")
|
|
|
|
| 3077 |
#################################################################################################################################################################
|
| 3078 |
#--------------------------------------------------[Helper main function]----------------------------------------------------------------------------------------
|
| 3079 |
#################################################################################################################################################################
|
|
|
|
| 3102 |
#################################################################################################################################################################
|
| 3103 |
|
| 3104 |
initial_opcode_counts = [
|
| 3105 |
+
{"opcode": "event_whenbroadcastreceived","count": 1},
|
| 3106 |
+
{"opcode": "control_forever","count": 1},
|
| 3107 |
+
{"opcode": "control_if","count": 1},
|
| 3108 |
+
{"opcode": "sensing_istouching","count": 1},
|
| 3109 |
+
{"opcode": "looks_hide","count": 1},
|
| 3110 |
+
{"opcode": "looks_switchbackdropto","count": 1},
|
| 3111 |
+
{"opcode": "event_broadcast","count": 1},
|
| 3112 |
+
{"opcode": "control_stop","count": 1}
|
| 3113 |
]
|
| 3114 |
pseudo_code="""
|
| 3115 |
+
when I receive [Game Start v]
|
| 3116 |
+
forever
|
| 3117 |
+
if <touching [obstacle v]?> then
|
| 3118 |
+
hide
|
| 3119 |
+
switch backdrop to [loose v]
|
| 3120 |
+
broadcast [Game Over v]
|
| 3121 |
+
stop all
|
| 3122 |
+
end
|
| 3123 |
end
|
| 3124 |
"""
|
| 3125 |
# print(pseudo_code)
|
|
|
|
| 3127 |
# all_generated_blocks = generate_plan(generated_output_json, initial_opcode_occurrences, pseudo_code)
|
| 3128 |
# processed_blocks= process_scratch_blocks(all_generated_blocks, generated_output_json)
|
| 3129 |
# renamed_blocks, renamed_counts = rename_blocks(processed_blocks, initial_opcode_occurrences)
|
| 3130 |
+
# #print(all_generated_blocks)
|
| 3131 |
# print("--------------\n\n")
|
| 3132 |
# print(processed_blocks)
|
| 3133 |
# print("--------------\n\n")
|
| 3134 |
+
# print(initial_opcode_occurrences)
|
| 3135 |
+
# print("--------------\n\n")
|
| 3136 |
# print(renamed_blocks)
|