# gbg.py - glass bead game # # CREATED 2021.05.17 ABS copied from randomEV.py # MODIFIED 2021.05.18 ABS added labels # MODIFIED 2021.05.24 ABS binary string representation # MODIFIED 2021.05.26 ABS binary string representation on input # MODIFIED 2021.05.27 ABS stop printing after size steps; added -m # MODIFIED 2021.05.28 ABS added building outcome table # MODIFIED 2021.05.31 ABS added -f final (target) value # MODIFIED 2021.06.08 ABS added stop on target # MODIFIED 2021.06.20 ABS debugged stop on target # MODIFIED 2022.07.26 ABS fixed colors # MODIFIED 2023.02.04 ABS tweaked; added scoring # MODIFIED 2023.02.05 ABS added bit flip # MODIFIED 2023.02.09 ABS added 'w' script command # MODIFIED 2023.02.23 ABS tweaked table output # MODIFIED 2023.03.06 ABS added -A & -X flags # MODIFIED 2023.03.07 ABS debugged # MODIFIED 2023.03.14 ABS fixed rule numbering # MODIFIED 2023.03.16 ABS tweaked # MODIFIED 2023.03.19 ABS fixed scoring # MODIFIED 2023.04.05 ABS debugged steps in scripting # # To Do: [_] better HTML (titles, headers) # from __future__ import print_function import sys import argparse import math # import numpy as np import random # START: debugWrite def debugWrite(flag, message, var): if (flag): print('gbg: DEBUG:', message, var, file=sys.stderr) # END: debugWrite # START: print_bead def print_bead(bead): if (bead == 0): print(" ") elif (bead == 1): print(" ") else: print("_ ") # END: print_bead # START: print_step def print_step(step_line, step_num, rule_num, loop_size, binary_beads): print("") if (args.abbrevFlag == False): for column in range(1, shown_size + 1): print_bead(step_line[column]) bgcolor="WHITE" if ((step_num == 0) or (step_num == "input")): bgcolor="#80FF80" if (binary_beads == args.final_binary): bgcolor="PINK" print("", step_num, "") print("", rule_num, "") print("", binary_beads, "") if (args.xorFlag == True): # debugWrite(args.debugFlag, "args.final_binary = ", args.final_binary) # debugWrite(args.debugFlag, "binary_beads = ", binary_beads) # target_binary = "0b" + args.final_binary # current_binary = "0b" + binary_beads target_binary = args.final_binary current_binary = binary_beads debugWrite(args.debugFlag, "target_binary =", target_binary) debugWrite(args.debugFlag, "current_binary =", current_binary) # debugWrite(args.debugFlag, "type(current_binary) =", type(current_binary)) # A = 0b1100 # debugWrite(args.debugFlag, "type(A) =", type(A)) # debugWrite(args.debugFlag, "int(target_binary, 2) =", int(target_binary, 2)) # debugWrite(args.debugFlag, "int(current_binary, 2) =", int(current_binary, 2)) differ = bin(int(target_binary, 2)^int(current_binary, 2)) debugWrite(args.debugFlag, "differ = ", differ) print("", differ.count("1"), "bits ") print("") if (loop_size == 0): # print to table file if ((binary_beads == args.final_binary) and (step > 0)): print(args.binary_start, binary_beads, step, rule_number, file=tf, sep=",") # END: print_step # START: apply_rule def apply_rule(a, b, c, rule): # cluster = a*4 + b*2 + c index = 2**cluster mask = (int(index) & int(flip_byte(rule))) result = mask/index return result # END: apply_rule # START: flip_byte def flip_byte(input_byte): # flipped_string = "" for i in range (0,8): reverse_i = i temp_mask = 2**reverse_i if ((input_byte & temp_mask) == 0): flipped_string = flipped_string + "0" else: flipped_string = flipped_string + "1" flipped_byte = int("0b" + flipped_string, 2) return flipped_byte # END: flip_byte # START: parse_binary_array def parse_binary_array(binary_string, binary_array, size): for column in range(0, size): binary_array[column] = int(binary_string[column]) # END: parse_binary_array # START: encode_binary_string def encode_binary_string(binary_array, size): temp_string = "" for column in range(0, size): if (binary_array[column] == 0): temp_string = temp_string + '0' else: temp_string = temp_string + '1' return(temp_string) # END: encode_binary_string # START: running (main) # parser = argparse.ArgumentParser(description='explore or play the Glass Bead Game; see: https://people.well.com/user/abs/Cyb/archive/c3m_1701.html#sec_1') parser.add_argument('-D', '--DEBUG', dest='debugFlag', action='store_true', help='debug write') parser.add_argument('-A', '--ABBREV', dest='abbrevFlag', action='store_true', help='abbreviated output (no beads)') parser.add_argument('-X', '--XOR', dest='xorFlag', action='store_true', help='xor current and target and count bits') parser.add_argument('-b', '--binary_start', dest='binary_start', default='0101010101', action='store', help='starting bead pattern in binary') parser.add_argument('-f', '--final_binary', dest='final_binary', default='1010101010', action='store', help='final bead pattern in binary') parser.add_argument('-m', '--max_steps', dest='max_steps', default=8192, action='store', help='maximum number of steps') parser.add_argument('-n', '--num_steps', dest='num_steps', default=8, action='store', help='number of steps to print') parser.add_argument('-r', '--rule', dest='rule', default=32, action='store', help='rule number of 2D binary cellular automaton') parser.add_argument('-s', '--size', dest='size', default=10, action='store', help='size of string of beads') parser.add_argument('-t', '--table_file', dest='table_file', default="table_map.txt", action='store', help='table file') parser.add_argument('-L', '--Loop', dest='Loop', default=False, action='store_true', help='stop when loop detected') parser.add_argument('-T', '--Target_stop', dest='Target_stop', default=False, action='store_true', help='stop when target reached') parser.add_argument('-S', '--Script', dest='Script', default=False, action='store_true', help='take script commands from standard input') parser.add_argument('-W', '--Wrap', dest='Wrap', default=False, action='store_true', help='wrap each line') args = parser.parse_args() num_steps = int(args.num_steps) max_steps = int(args.max_steps) rule_number = int(args.rule) shown_size = int(args.size) rule_score = shown_size*shown_size flip_score = shown_size*shown_size*shown_size true_size = shown_size + 2 Wrap_lines = (args.Wrap == True) Script_control = (args.Script == True) Target_stop = (args.Target_stop == True) cumulative_score = 0 rule_changes = 0 bit_flips = 0 PrintRow = True debugWrite(args.debugFlag, "======== num_steps =", num_steps) debugWrite(args.debugFlag, "rule_number =", rule_number) debugWrite(args.debugFlag, "shown_size =", shown_size) debugWrite(args.debugFlag, "true_size =", true_size) debugWrite(args.debugFlag, "args.table_file =", args.table_file) debugWrite(args.debugFlag, "args.binary_start =", args.binary_start) debugWrite(args.debugFlag, "lenght of args.binary_start =", len(args.binary_start)) debugWrite(args.debugFlag, "Wrap_lines =", Wrap_lines) debugWrite(args.debugFlag, "Script_control =", Script_control) debugWrite(args.debugFlag, "rule_score =", rule_score) debugWrite(args.debugFlag, "flip_score =", flip_score) tf = open(args.table_file, 'w') # 9 = bad value start_array = [] for column in range(0, true_size): start_array.append(9) start_binary_string = '0' + args.binary_start + '0' # debugWrite(args.debugFlag, "start_binary_string =", start_binary_string) parse_binary_array(start_binary_string, start_array, true_size) if (Wrap_lines): start_array[0] = start_array[-2] start_array[-1] = start_array[1] else: start_array[0] = 0 start_array[-1] = 0 # debugWrite(args.debugFlag, "start_array =", start_array) prev_array = [] step_array = [] for column in range(0, true_size): prev_array.append(int(start_array[column])) if (Wrap_lines): prev_array[0] = prev_array[-2] prev_array[-1] = prev_array[1] else: prev_array[0] = 0 prev_array[-1] = 0 debugWrite(args.debugFlag, "start_array: ", start_array) step = 0 debugWrite(args.debugFlag, ">>>>>>>> step =", step) true_beads = encode_binary_string(start_array, true_size) display_beads = true_beads[1:-1] print("

starting beads =", display_beads, "; target beads =", args.final_binary, "

") print("

") print("") print("") if (args.abbrevFlag == False): for column in range(1, shown_size + 1): print("") print("") print("") print("") if (args.xorFlag == True): print("") print("") print_step(start_array, "input", "-", 0, display_beads) if (display_beads == args.final_binary): # found target print("
", column, "step or
action
rule/bit
number
binary
beads
xor current
and final,
count bits
") print("target found after 0 steps") print("score = 0") sys.exit() # KLUDGE for column in range(0, true_size): step_array.append(-1) step_stack = [] step_stack.append(encode_binary_string(start_array, true_size)) stack_size = 1 # script case if (Script_control == True): cumulative_steps = 1 rule_number = 0 Stepping = False # # process script # for line in sys.stdin: stripped_line = line.rstrip('\n') fields = stripped_line.split(" ") debugWrite(args.debugFlag, "fields =", fields) if (fields[0] == 'r'): rule_number = int(fields[1]) if (Stepping): cumulative_score = cumulative_score + rule_score debugWrite(args.debugFlag, "r cumulative_score =", cumulative_score) rule_changes = rule_changes + 1 debugWrite(args.debugFlag, "new rule_number =", rule_number) # end if if (fields[0] == 'w'): int_wrap_lines = int(fields[1]) if (int_wrap_lines == 0): Wrap_lines = False else: Wrap_lines = True if (Stepping): cumulative_score = cumulative_score + rule_score debugWrite(args.debugFlag, "w cumulative_score =", cumulative_score) rule_changes = rule_changes + 1 debugWrite(args.debugFlag, "new Wrap_lines =", Wrap_lines) if (PrintRow): true_beads = encode_binary_string(step_array, true_size) display_beads = true_beads[1:-1] print_step(step_array, "wrap", int_wrap_lines, 0, display_beads) # end if if (fields[0] == 'f'): Stepping = True flip_bit = int(fields[1]) debugWrite(args.debugFlag, "flipping bit", flip_bit) bit_flips = bit_flips + 1 cumulative_score = cumulative_score + flip_score debugWrite(args.debugFlag, "f cumulative_score =", cumulative_score) if (step_array[flip_bit] == 0): step_array[flip_bit] = 1 else: step_array[flip_bit] = 0 if (PrintRow): true_beads = encode_binary_string(step_array, true_size) display_beads = true_beads[1:-1] print_step(step_array, "flip", flip_bit, 0, display_beads) if (display_beads == args.final_binary): # found target print("") print("

") print("target found; steps (1 point): ", cumulative_steps - 1, "; rule/wrap changes (", rule_score, " points): ", rule_changes, "; bit flips (", flip_score, " points): ", bit_flips, "", sep="") print("

") print("score = ", cumulative_score, "") sys.exit() # end elif if (fields[0] == 's'): Stepping = True max_steps = int(fields[1]) cumulative_score = cumulative_score + max_steps debugWrite(args.debugFlag, "s cumulative_score =", cumulative_score) debugWrite(args.debugFlag, "new max_steps =", max_steps) # process steps in script for step in range(0, max_steps): debugWrite(args.debugFlag, ">>>>>>>> step =", step) for column in range(1, shown_size + 1): step_array[column] = apply_rule(prev_array[column - 1], prev_array[column], prev_array[column + 1], rule_number) if (Wrap_lines): step_array[0] = step_array[-2] step_array[-1] = step_array[1] else: step_array[0] = 0 step_array[-1] = 0 for column in range(0, true_size): prev_array[column] = step_array[column] debugWrite(args.debugFlag, "step_array: ", step_array) if (PrintRow): true_beads = encode_binary_string(step_array, true_size) display_beads = true_beads[1:-1] print_step(step_array, cumulative_steps, rule_number, 0, display_beads) if (display_beads == args.final_binary): # found target print("") print("

") print("target found after", cumulative_steps, "steps,", rule_changes, "rule/wrap changes and", bit_flips, "bit flips") print("

") print("score = ", cumulative_score, "") sys.exit() cumulative_steps = cumulative_steps + 1 # end for step # end if if ((fields[0] != 's') and (fields[0] != 'f') and (fields[0] != 'r') and (fields[0] != 'w')): print("ERROR: illegal script command:", fields[0], file=sys.stderr) sys.exit() # end else # end for line print("") sys.exit() # no script case for step in range(1, max_steps): debugWrite(args.debugFlag, ">>>>>>>> step =", step) if (step % 1000 == 0): print("++++++++ step =", step, file=sys.stderr) if (step > num_steps): # just crossed the line if (PrintRow): print("*") PrintRow = False for column in range(1, shown_size + 1): step_array[column] = apply_rule(prev_array[column - 1], prev_array[column], prev_array[column + 1], rule_number) if (Wrap_lines): step_array[0] = step_array[-2] step_array[-1] = step_array[1] else: step_array[0] = 0 step_array[-1] = 0 for column in range(0, true_size): prev_array[column] = step_array[column] debugWrite(args.debugFlag, "step_array: ", step_array) step_stack.append(encode_binary_string(step_array, true_size)) stack_size = stack_size + 1 loop_size = 0 for depth in range(0, stack_size - 1): # debugWrite(args.debugFlag, "depth =", depth) # debugWrite(args.debugFlag, "step_stack[depth] =", step_stack[depth]) # debugWrite(args.debugFlag, "step_stack[-1] =", step_stack[-1]) # check if latest step is a repeat if (step_stack[-1] == step_stack[depth]): PrintRow = True loop_size = stack_size - depth - 1 debugWrite(args.debugFlag, "loop_size =", loop_size) break if (PrintRow): true_beads = encode_binary_string(step_array, true_size) display_beads = true_beads[1:-1] print_step(step_array, step, rule_number, loop_size, display_beads) if (display_beads == args.final_binary): # found target print("") print("target found after", step, "steps") sys.exit() if (loop_size > 0): break # debugWrite(args.debugFlag, "step_stack =", step_stack) print("") if (loop_size == 0): print("no loop after", max_steps, "steps") print(args.binary_start, display_beads, "U", rule_number, file=tf, sep=",") elif (loop_size > 0): print("transient =", step - loop_size, " ") print("loop =", loop_size, "") print("

") # # END: running (main)