33import os
44import shutil
55import time
6-
76import pygame
87
98os .chdir (os .path .dirname (__file__ ))
@@ -339,6 +338,24 @@ def approve_current(now):
339338 f .close ()
340339 print (f"{ left_nodes } assigned to { right_name } " )
341340
341+ # Save approved nodes to individual spell file
342+ SPELL_JSON_DIR = os .path .abspath ("patterns_by_spell" )
343+ os .makedirs (SPELL_JSON_DIR , exist_ok = True )
344+
345+ spell_json_path = os .path .join (SPELL_JSON_DIR , f"{ right_name } .json" )
346+ if os .path .exists (spell_json_path ):
347+ with open (spell_json_path , "r" ) as sf :
348+ spell_data = json .load (sf )
349+ else :
350+ spell_data = []
351+
352+ if list (left_nodes ) not in spell_data :
353+ spell_data .append (list (left_nodes ))
354+
355+ with open (spell_json_path , "w" ) as sf :
356+ json .dump (spell_data , sf , indent = 4 )
357+
358+
342359 # Remember the current index before reloading
343360 current_index = left_index
344361
@@ -365,51 +382,91 @@ def reject_current(now):
365382
366383 left_filename = left_files [left_index ]
367384 left_path = left_paths [left_index ]
368- target_path = os .path .join (REJECTED_FOLDER , left_filename )
369385 left_nodes = left_nodelist [left_index ]
370386 left_nodelist .pop (0 )
371387
372- # Move instead of copy
388+ is_triangle = isinstance (left_nodes , tuple ) and len (left_nodes ) == 3
389+ triangle_key = "triangle"
390+
391+ # Folder routing
392+ if is_triangle :
393+ target_dir = os .path .join (OUTPUT_FOLDER , triangle_key )
394+ else :
395+ target_dir = REJECTED_FOLDER
396+
397+ os .makedirs (target_dir , exist_ok = True )
398+ target_path = os .path .join (target_dir , left_filename )
399+
373400 shutil .move (left_path , target_path )
374401 action_stack .append (("rejected" , left_index , target_path , left_path ))
375-
376- # prints that the nodes were rejected
377402 node_stack .append (left_nodes )
378- right_name = os .path .splitext (right_files [right_index % len (right_files )])[0 ]
379- file_exists = False
403+
404+ print (f"{ left_nodes } was rejected" )
405+
406+ # --- spell_patterns.json ---
380407 try :
381- with open ("spell_patterns.json" , "r" ):
382- file_exists = True
408+ with open ("spell_patterns.json" , "r" ) as f :
409+ data = json . load ( f )
383410 except FileNotFoundError :
384- pass
385- if file_exists :
386- f = open ("spell_patterns.json" , "r" )
387- data = json .load (f )
388- f .close ()
411+ data = {"valid_patterns" : 0 }
412+
413+ if is_triangle :
414+ if triangle_key not in data :
415+ data [triangle_key ] = {"patterns" : [], "valid_patterns" : 0 }
416+ if list (left_nodes ) not in data [triangle_key ]["patterns" ]:
417+ data [triangle_key ]["patterns" ].append (list (left_nodes ))
418+ data [triangle_key ]["valid_patterns" ] += 1
419+ data ["valid_patterns" ] += 1
420+ print (f"{ left_nodes } saved to triangle" )
421+ else :
422+ right_name = os .path .splitext (right_files [right_index % len (right_files )])[0 ]
389423 if right_name in data :
390424 if list (left_nodes ) in data [right_name ]["patterns" ]:
391425 data [right_name ]["patterns" ].remove (list (left_nodes ))
392- if len (data [right_name ]["patterns" ]) == 0 :
393- data .pop (right_name , None )
394- else :
395- data [right_name ]["valid_patterns" ] -= 1
426+ data [right_name ]["valid_patterns" ] -= 1
396427 data ["valid_patterns" ] -= 1
397- f = open ("spell_patterns.json" , "w+" )
398- f .write (json .dumps (data , indent = 4 ))
399- f .close ()
428+ if data [right_name ]["valid_patterns" ] == 0 :
429+ del data [right_name ]
400430
401- # Remember the current index before reloading
402- current_index = left_index
431+ with open ( "spell_patterns.json" , "w" ) as f :
432+ json . dump ( data , f , indent = 4 )
403433
404- # After moving, reload the image list
405- reload_images ()
434+ # --- patterns_by_spell/triangle.json ---
435+ if is_triangle :
436+ triangle_json_path = os .path .join ("patterns_by_spell" , f"{ triangle_key } .json" )
437+ os .makedirs ("patterns_by_spell" , exist_ok = True )
406438
407- # Stay at the same index after removing, unless we're at the end
408- if current_index >= len (left_paths ):
409- left_index = max (0 , len (left_paths ) - 1 )
410- else :
411- left_index = current_index
439+ try :
440+ with open (triangle_json_path , "r" ) as tf :
441+ triangle_data = json .load (tf )
442+ except FileNotFoundError :
443+ triangle_data = []
444+
445+ if list (left_nodes ) not in triangle_data :
446+ triangle_data .append (list (left_nodes ))
447+
448+ with open (triangle_json_path , "w" ) as tf :
449+ json .dump (triangle_data , tf , indent = 4 )
412450
451+ # --- rejected.json (ONLY non-triangle patterns) ---
452+ if not is_triangle :
453+ rejected_json_path = os .path .join ("rejected.json" )
454+ try :
455+ with open (rejected_json_path , "r" ) as rj :
456+ rejected_data = json .load (rj )
457+ except FileNotFoundError :
458+ rejected_data = {"rejected_patterns" : []}
459+
460+ if list (left_nodes ) not in rejected_data ["rejected_patterns" ]:
461+ rejected_data ["rejected_patterns" ].append (list (left_nodes ))
462+
463+ with open (rejected_json_path , "w" ) as rj :
464+ json .dump (rejected_data , rj , indent = 4 )
465+
466+ # --- Finalization ---
467+ current_index = left_index
468+ reload_images ()
469+ left_index = max (0 , len (left_paths ) - 1 ) if current_index >= len (left_paths ) else current_index
413470 approval_time = now
414471 message_text = "Rejected!"
415472 message_color = RED
@@ -420,33 +477,93 @@ def go_back(now):
420477 global left_index , approval_time , show_message , message_text , message_color
421478 if action_stack :
422479 action , index , target_path , original_path = action_stack .pop ()
480+ node = node_stack .pop ()
481+ left_nodelist .insert (0 , node ) # Restore the node
482+ print (f"{ node } was retrieved" )
423483
424- # adds the nodes back to the original list
425- left_nodelist .insert (0 , node_stack .pop ())
426-
427- print (f"{ left_nodelist [0 ]} was retrieved" )
484+ # Restore the image file
428485 if os .path .exists (target_path ):
429- # Make sure the directory exists
430486 os .makedirs (os .path .dirname (original_path ), exist_ok = True )
431- # Move the file back to its original location
432487 shutil .move (target_path , original_path )
433-
434- # Reload images after moving it back
435488 reload_images ()
436489
437- # Find the index of the restored file
438490 try :
439491 restored_filename = os .path .basename (original_path )
440492 restored_index = left_files .index (restored_filename )
441493 left_index = restored_index
442494 except ValueError :
443- # If for some reason we can't find the file, just stay at current index
444495 pass
445496
446- approval_time = now
447- message_text = "Undone"
448- message_color = GRAY
449- show_message = True
497+ # Load spell_patterns.json
498+ try :
499+ with open ("spell_patterns.json" , "r" ) as f :
500+ data = json .load (f )
501+ except FileNotFoundError :
502+ data = {"valid_patterns" : 0 }
503+
504+ node_list = list (node )
505+
506+ if action == "approved" :
507+ try :
508+ spell_name = os .path .basename (os .path .dirname (target_path ))
509+ except IndexError :
510+ spell_name = None
511+
512+ if spell_name and spell_name in data :
513+ if node_list in data [spell_name ]["patterns" ]:
514+ data [spell_name ]["patterns" ].remove (node_list )
515+ data [spell_name ]["valid_patterns" ] -= 1
516+ data ["valid_patterns" ] -= 1
517+ if data [spell_name ]["valid_patterns" ] == 0 :
518+ del data [spell_name ]
519+
520+ spell_json_path = os .path .join ("patterns_by_spell" , f"{ spell_name } .json" )
521+ if os .path .exists (spell_json_path ):
522+ with open (spell_json_path , "r" ) as sf :
523+ spell_data = json .load (sf )
524+ if node_list in spell_data :
525+ spell_data .remove (node_list )
526+ with open (spell_json_path , "w" ) as sf :
527+ json .dump (spell_data , sf , indent = 4 )
528+
529+ elif action == "rejected" :
530+ is_triangle = isinstance (node , tuple ) and len (node ) == 3
531+ triangle_key = "triangle"
532+
533+ if is_triangle and triangle_key in data :
534+ if node_list in data [triangle_key ]["patterns" ]:
535+ data [triangle_key ]["patterns" ].remove (node_list )
536+ data [triangle_key ]["valid_patterns" ] -= 1
537+ data ["valid_patterns" ] -= 1
538+ if data [triangle_key ]["valid_patterns" ] == 0 :
539+ del data [triangle_key ]
540+
541+ triangle_json_path = os .path .join ("patterns_by_spell" , f"{ triangle_key } .json" )
542+ if os .path .exists (triangle_json_path ):
543+ with open (triangle_json_path , "r" ) as tf :
544+ triangle_data = json .load (tf )
545+ if node_list in triangle_data :
546+ triangle_data .remove (node_list )
547+ with open (triangle_json_path , "w" ) as tf :
548+ json .dump (triangle_data , tf , indent = 4 )
549+
550+ # Remove from rejected.json
551+ rejected_json_path = os .path .join ("rejected.json" )
552+ if os .path .exists (rejected_json_path ):
553+ with open (rejected_json_path , "r" ) as rj :
554+ rejected_data = json .load (rj )
555+ if node_list in rejected_data ["rejected_patterns" ]:
556+ rejected_data ["rejected_patterns" ].remove (node_list )
557+ with open (rejected_json_path , "w" ) as rj :
558+ json .dump (rejected_data , rj , indent = 4 )
559+
560+ with open ("spell_patterns.json" , "w" ) as f :
561+ json .dump (data , f , indent = 4 )
562+
563+ approval_time = now
564+ message_text = "Undone"
565+ message_color = GRAY
566+ show_message = True
450567
451568
452569# --- Main Loop ---
@@ -478,12 +595,14 @@ def main():
478595 for event in pygame .event .get ():
479596 if event .type == pygame .QUIT :
480597 running = False
598+ with open ("patterns_nodes.txt" , "w" ) as f :
599+ f .write (str (left_nodelist ))
481600
482601 elif event .type == pygame .KEYDOWN :
483- if event .key == pygame .K_ESCAPE :
484- running = False
485- elif event .key == pygame .K_RETURN :
602+ if event .key == pygame .K_RETURN or event .key == pygame .K_y :
486603 approve_current (now )
604+ elif event .key == pygame .K_n :
605+ reject_current (now )
487606 elif event .key == pygame .K_LEFT and right_paths :
488607 key_held_left = True
489608 next_hold_time = now
@@ -493,9 +612,10 @@ def main():
493612 elif event .key == pygame .K_f :
494613 fullscreen = not fullscreen
495614 pygame .display .set_mode (
496- (WIDTH , HEIGHT ),
497- pygame .FULLSCREEN if fullscreen else pygame .RESIZABLE ,
498- )
615+ (WIDTH , HEIGHT ),
616+ pygame .FULLSCREEN if fullscreen else pygame .RESIZABLE ,
617+ )
618+
499619
500620 elif event .type == pygame .KEYUP :
501621 if event .key == pygame .K_LEFT :
@@ -530,4 +650,4 @@ def main():
530650
531651
532652if __name__ == "__main__" :
533- main ()
653+ main ()
0 commit comments