You do not store a matrix, you store columns as "sentences", using zip
you create rows from them:
c = ["SHOW", "ME ", "THIS"]
r = [' '.join(row) for row in zip(*c)]
print (c)
for n in r:
print(n)
Output:
['SHOW', 'ME ', 'THIS']
S M T
H E H
O I
W S
Now you just need to mutate the content - you can slice the strings:
c[1] = "!"+c[1][:-1]
r = [' '.join(row) for row in zip(*c)]
for n in r:
print(n)
Output:
S ! T
H M H
O E I
W S
A matrix would be cumbersome, you want to scroll single columns down while others stand still and might want to replace single characters. Using a matrix would need you to downshift a lot all the time, far easier to modify a "column-sentence" (as above) or a list of strings:
from string import ascii_letters, digits
from itertools import product
import random
import os
import time
random.seed(42) # remove for more randomness
numCols = 10
numRows = 20
allCoods = list(product(range(numCols),range(numRows))) # for single char replacement
pri = ascii_letters + digits + '`?=)(/&%$§"!´~#' # thats what we display
# cred: https://stackoverflow.com/a/684344/7505395
def cls():
os.system('cls' if os.name=='nt' else 'clear')
def modCol(columns, which):
for (c,r) in which:
# replace change random characters
newOne = random.choice(pri)
columns[c] = columns[c][:r]+[newOne]+columns[c][r+1:]
for i in range(len(columns)):
if (random.randint(0,5) > 2):
# scroll some lines down by 1
columns[i].insert(0,random.choice(pri))
columns[i] = columns[i][:-1]
# creates random data for columns
cols = [random.choices(pri ,k=numRows ) for _ in range(numCols)]
while True:
cls()
# zip changes your columns-list into a row-tuple, the joins for printing
print ( '\n'.join(' '.join(row) for row in zip(*cols)))
time.sleep(1)
# which characters to change?
choi = random.choices(allCoods, k=random.randint(0,(numCols*numRows)//3))
modCol(cols, choi )