Advertisement
Hinski2

Untitled

May 15th, 2024
40
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.90 KB | None | 0 0
  1. from queue import PriorityQueue
  2. from itertools import combinations
  3. from random import shuffle
  4. from copy import deepcopy
  5.  
  6. yes, idk, no = [1, 0, -1] # pseudo enum
  7. row_enum, col_enum = range(2) #psudo enum
  8.    
  9. def make_line_poss(empty_no, blocks_no, ones):
  10.     line_poss = []
  11.     for p in combinations(range(empty_no + blocks_no), blocks_no):
  12.         selected = [no] * (empty_no + blocks_no)
  13.         idx = 0
  14.         for val in p:
  15.             selected[val] = idx
  16.             idx += 1
  17.        
  18.         res = [ones[val] + [-1] if val > -1 else [-1] for val in selected]
  19.         res = [item for sublist in res for item in sublist][:-1]
  20.         line_poss.append(res)
  21.     return line_poss
  22.  
  23. def make_poss(lines, n):
  24.     lines_poss = []
  25.     for line in lines:
  26.         blocks_no = len(line)
  27.         empty_no = n - sum(line) - blocks_no + 1
  28.         ones = [[1] * pixel for pixel in line]
  29.         line_poss = make_line_poss(empty_no, blocks_no, ones)
  30.         lines_poss.append(line_poss)
  31.    
  32.     return lines_poss
  33.  
  34. # wybiera idx lini które jeszcze nie zostały rozwiązane całkowicie
  35. def select_not_solved(poss, done, enum):
  36.     s = [len(i) for i in poss]
  37.     return [(liczba_mozliwosci, i, enum) for i, liczba_mozliwosci in enumerate(s) if done[i] == 0]
  38.  
  39. def get_same_pixels(poss, line):
  40.     poss_no = len(poss)
  41.     if poss_no == 0: return []
  42.    
  43.     line_len = len(poss[0])
  44.     sum = [0] * line_len
  45.     for p in poss:
  46.         for i in range(line_len):
  47.             sum[i] += 1 if p[i] == yes else 0
  48.    
  49.     same_pixels = []
  50.     for i in range(line_len):
  51.         if sum[i] == 0 and line[i] != no: same_pixels.append([i, no])
  52.         elif sum[i] == poss_no and line[i] != yes: same_pixels.append([i, yes])
  53.    
  54.     return same_pixels
  55.  
  56. def check_done(i, enum, cols_done, rows_done):
  57.     if enum == row_enum: return rows_done[i]
  58.     return cols_done[i]
  59.  
  60. def check_solved(rows_done, cols_done):
  61.     return True if 0 not in rows_done and 0 not in cols_done else False
  62.  
  63. def get_col(matrix, j):
  64.     return [matrix[i][j] for i in range(len(matrix))]
  65.  
  66. def update_done(enum, i, matrix, rows_done, cols_done):
  67.     line = matrix[i] if enum == row_enum else get_col(matrix, i)
  68.     if idk not in line:
  69.         if enum == row_enum: rows_done[i] = 1
  70.         else: cols_done[i] = 1
  71.  
  72. def update_poss(poss, i, val):
  73.     return [p for p in poss if p[i] == val]
  74.  
  75. def removed_poss(poss, i, val):
  76.     return [p for p in poss if p[i] != val]
  77.  
  78. def valid(matrix, rows, cols):
  79.     def get_segments(line):
  80.         segments = []
  81.         count = 0
  82.         for value in line:
  83.             if value == 1:
  84.                 count += 1
  85.             elif count > 0:
  86.                 segments.append(count)
  87.                 count = 0
  88.         if count > 0:
  89.             segments.append(count)
  90.         return segments
  91.  
  92.     # Sprawdzamy wiersze
  93.     for i, row in enumerate(matrix):
  94.         if get_segments(row) != rows[i]:
  95.             return False
  96.  
  97.     # Sprawdzamy kolumny
  98.     num_cols = len(matrix[0])
  99.     for j in range(num_cols):
  100.         col = [matrix[i][j] for i in range(len(matrix))]
  101.         if get_segments(col) != cols[j]:
  102.             return False
  103.  
  104.     return True
  105.  
  106. def wypisz(matrix):
  107.     for i in range(len(matrix)):
  108.         for j in range(len(matrix[0])):
  109.             print(matrix[i][j], end=' ')
  110.             if matrix[i][j] != -1: print(' ', end='')
  111.         print()
  112.     print()
  113.    
  114.  
  115. def get_coll(matrix, j):
  116.     return [matrix[i][j] for i in range(len(matrix))]
  117.  
  118. def give_back_removed_poss(n, m, removed_poss_rows, removed_poss_cols, rows_poss, cols_poss):
  119.     for g in range(n):
  120.         rows_poss[g] += removed_poss_rows[g]
  121.         removed_poss_rows[g] = []
  122.     for g in range(m):
  123.         cols_poss[g] += removed_poss_cols[g]
  124.         removed_poss_cols[g] = []
  125.  
  126. def removed_poss(poss, i, val):
  127.     return [p for p in poss if p[i] != val]
  128.  
  129. def find_ans(matrix, rows_poss, cols_poss, rows_done, cols_done, rows, cols):
  130.     # wypisz(matrix)
  131.     # szukam tego co moge ustawić
  132.     not_solved_rows = []
  133.     not_solved_cols = []
  134.     lines_todo = []
  135.    
  136.     removed_poss_rows = [[] for _ in range(len(matrix))]
  137.     removed_poss_cols = [[] for _ in range(len(matrix[0]))]
  138.    
  139.     #sprawdzenie
  140.     for j in range(len(rows_poss)):
  141.         if len(rows_poss[j]) == 0 and not rows_done[j]:
  142.             return []
  143.        
  144.     for j in range(len(cols_done)):
  145.         if len(cols_poss[j]) == 0 and not cols_done[j]:
  146.             return []
  147.    
  148.     # ustawiam to co moge
  149.     solved, change = False, True
  150.     while not solved and change:
  151.         change = False
  152.         not_solved_rows = select_not_solved(rows_poss, rows_done, row_enum)
  153.         not_solved_cols = select_not_solved(cols_poss, cols_done, col_enum)
  154.         lines_todo = sorted(not_solved_cols + not_solved_rows) # sortuje je po najmniejszej ilości możliwości na które można ułożyć linie
  155.        
  156.         # ustawia pixele o których wiemy jak będą wyglądały
  157.         for ammount, i, enum in lines_todo:
  158.             if ammount == 0:
  159.                 give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows, removed_poss_cols, rows_poss, cols_poss)
  160.                 return []
  161.            
  162.             if not check_done(i, enum, cols_done, rows_done):
  163.                 poss = rows_poss[i] if enum == row_enum else cols_poss[i] # możliwe wypełnienia lini
  164.                 line = matrix[i] if enum == row_enum else get_coll(matrix, i)
  165.                 same_pixels = get_same_pixels(poss, line)
  166.                
  167.                 for j, val in same_pixels:
  168.                     r_idx, c_idx = (i, j) if row_enum == enum else (j, i)
  169.                     if matrix[r_idx][c_idx] == idk:
  170.                         if matrix[r_idx][c_idx] != val:
  171.                             matrix[r_idx][c_idx] = val
  172.                             change = True
  173.  
  174.                             # usówamie możliwości które się nie zgadzająz nowym pixelem
  175.                             if enum != row_enum:
  176.                                 removed_poss_rows[r_idx] += removed_poss(rows_poss[r_idx], c_idx, val)
  177.                                 rows_poss[r_idx] = update_poss(rows_poss[r_idx], c_idx, val)
  178.                             else:
  179.                                 removed_poss_cols[c_idx] += removed_poss(cols_poss[c_idx], r_idx, val)
  180.                                 cols_poss[c_idx] = update_poss(cols_poss[c_idx], r_idx, val)
  181.                                
  182.                 update_done(enum, i, matrix, rows_done, cols_done) # sprawdza czy linia jest ukończona
  183.         solved = check_solved(rows_done, cols_done)
  184.  
  185.     # jeśli mam gotowy nonogram to go zwracam
  186.     #sprawdzenie
  187.     for j in range(len(rows_poss)):
  188.         if len(rows_poss[j]) == 0 and not rows_done[j]:
  189.             give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows, removed_poss_cols, rows_poss, cols_poss)
  190.             return []
  191.        
  192.     for j in range(len(cols_done)):
  193.         if len(cols_poss[j]) == 0 and not cols_done[j]:
  194.             give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows, removed_poss_cols, rows_poss, cols_poss)
  195.             return []
  196.        
  197.     if solved:
  198.         if valid(matrix, rows, cols):
  199.             give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows, removed_poss_cols, rows_poss, cols_poss)
  200.             return matrix
  201.         else:
  202.             give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows, removed_poss_cols, rows_poss, cols_poss)
  203.             return []
  204.    
  205.     # jeśli nie jsest gotowy to robie kopie oraz ustawiam ten wiersz / kolumne
  206.         # którą ma najmniej możliwości ustawienia
  207.         # jak ją już ustawie to robie wywołąnie find_ans jeśli zwróci [] to ustawiam kolejną możliwość
  208.         # dla wiersza/kolumny aż do końca możliwości
  209.         # jeśli przejżałem już wszystkie możliwości i nic nie znalazłem to zwracam []
  210.    
  211.     not_solved_rows = select_not_solved(rows_poss, rows_done, row_enum)
  212.     not_solved_cols = select_not_solved(cols_poss, cols_done, col_enum)
  213.     lines_todo = sorted(not_solved_cols + not_solved_rows) # sortuje je po najmniejszej ilości możliwości na które można ułożyć linie
  214.    
  215.     _, i, enum = lines_todo[0]
  216.     to_check = deepcopy(rows_poss[i] if enum == row_enum else cols_poss[i])
  217.     for u in to_check:
  218.         _matrix = deepcopy(matrix)
  219.         removed_poss_rows2 = [[] for _ in range(len(matrix))]
  220.         removed_poss_cols2 = [[] for _ in range(len(matrix[0]))]
  221.         _rows_done = deepcopy(rows_done)
  222.         _cols_done = deepcopy(cols_done)
  223.        
  224.         for j in range(len(u)):
  225.             val = u[j]
  226.             r_idx, c_idx = (i, j) if row_enum == enum else (j, i)
  227.             if _matrix[r_idx][c_idx] == idk:
  228.                 _matrix[r_idx][c_idx] = val
  229.  
  230.                 # usówamie możliwości które się nie zgadzająz nowym pixelem
  231.                 if enum != row_enum:
  232.                     removed_poss_rows2[r_idx] += removed_poss(rows_poss[r_idx], c_idx, val)
  233.                     rows_poss[r_idx] = update_poss(rows_poss[r_idx], c_idx, val)
  234.                 else:
  235.                     removed_poss_cols2[c_idx] += removed_poss(cols_poss[c_idx], r_idx, val)
  236.                     cols_poss[c_idx] = update_poss(cols_poss[c_idx], r_idx, val)
  237.                
  238.         update_done(enum, i, _matrix, _rows_done, _cols_done) # sprawdza czy linia jest ukończona
  239.        
  240.         if check_solved(_rows_done, _cols_done):
  241.             if valid(_matrix, rows, cols): return _matrix
  242.             else:
  243.                 give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows2, removed_poss_cols2, rows_poss, cols_poss)
  244.                 continue
  245.        
  246.         # wszystko już jest ustawione
  247.         ans = find_ans(_matrix, rows_poss, cols_poss, _rows_done, _cols_done, rows, cols)
  248.         give_back_removed_poss(len(matrix), len(matrix[0]), removed_poss_rows2, removed_poss_cols2, rows_poss, cols_poss)
  249.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement