code.pablomurad.com

matrix-ss

Matrix digital rain screensavers for the terminal

matrix_dna.py raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#!/usr/bin/env python3
import curses
import random
import time

def main(stdscr):
    # configura terminal
    curses.curs_set(0)
    stdscr.nodelay(True)
    stdscr.timeout(100)

    sh, sw = stdscr.getmaxyx()
    columns = [0] * sw
    dna_pairs = {}  # pares de bases complementares por posição
    helix_offset = 0  # offset para animação da hélice

    # bases do DNA
    dna_bases = ['A', 'T', 'G', 'C']
    
    # pares complementares
    complement = {'A': 'T', 'T': 'A', 'G': 'C', 'C': 'G'}
    
    # sequências de DNA famosas/interessantes
    famous_sequences = [
        "ATCGATCGATCG",  # sequência repetitiva
        "AAATTTGGGCCC",  # blocos de bases
        "ACGTACGTACGT",  # padrão alternado
        "TTAGGGTTAGGG",  # telômero humano
        "GAATTCGAATTC",  # sítio de restrição EcoRI
    ]

    # inicializa cores para DNA
    curses.start_color()
    curses.use_default_colors()
    curses.init_pair(1, curses.COLOR_RED, -1)        # Adenina (A)
    curses.init_pair(2, curses.COLOR_BLUE, -1)       # Timina (T)
    curses.init_pair(3, curses.COLOR_GREEN, -1)      # Guanina (G)
    curses.init_pair(4, curses.COLOR_YELLOW, -1)     # Citosina (C)
    curses.init_pair(5, curses.COLOR_WHITE, -1)      # conectores
    curses.init_pair(6, curses.COLOR_CYAN, -1)       # destaque
    curses.init_pair(7, curses.COLOR_MAGENTA, -1)    # sequências especiais

    base_colors = {
        'A': curses.color_pair(1),  # vermelho
        'T': curses.color_pair(2),  # azul
        'G': curses.color_pair(3),  # verde
        'C': curses.color_pair(4),  # amarelo
    }

    sequence_timer = 0
    current_sequence = ""
    sequence_pos = 0

    while True:
        key = stdscr.getch()
        if key == ord('q'):
            break

        helix_offset += 0.1  # animação da dupla hélice

        # gerencia sequências especiais
        sequence_timer += 1
        if sequence_timer > random.randint(200, 400):
            current_sequence = random.choice(famous_sequences)
            sequence_pos = 0
            sequence_timer = 0

        for x in range(sw):
            y = columns[x]
            
            # escolhe base de DNA
            if current_sequence and x == sw // 2 and sequence_pos < len(current_sequence):
                base = current_sequence[sequence_pos]
                sequence_pos += 1
                color = curses.color_pair(7)  # magenta para sequências especiais
                attr = curses.A_BOLD | curses.A_BLINK
            else:
                base = random.choice(dna_bases)
                color = base_colors[base]
                attr = curses.A_BOLD if random.randint(1, 10) == 1 else 0
            
            # desenha a base
            try:
                stdscr.addch(y, x, base, color | attr)
            except curses.error:
                pass

            # armazena par complementar para desenhar a dupla hélice
            dna_pairs[(x, y)] = complement[base]

            columns[x] = 0 if y >= sh - 1 else y + 1

        # desenha dupla hélice (pares complementares)
        for (x, y), comp_base in list(dna_pairs.items()):
            # calcula posição do par complementar com efeito helix
            helix_x = x + int(3 * math.sin(y * 0.2 + helix_offset))
            
            if 0 <= helix_x < sw and y < sh:
                try:
                    # desenha base complementar
                    comp_color = base_colors[comp_base]
                    stdscr.addch(y, helix_x, comp_base, comp_color)
                    
                    # desenha conector (ligação de hidrogênio)
                    if abs(helix_x - x) > 1:
                        connector_x = (x + helix_x) // 2
                        if 0 <= connector_x < sw:
                            connector_char = '─' if abs(helix_x - x) <= 3 else '~'
                            stdscr.addch(y, connector_x, connector_char, 
                                       curses.color_pair(5) | curses.A_DIM)
                except curses.error:
                    pass
            
            # remove pares antigos
            if y >= sh:
                del dna_pairs[(x, y)]

        # informações de DNA no topo
        try:
            dna_info = f"DNA SEQUENCER v3.2 | Bases: A={base_colors['A']} T={base_colors['T']} G={base_colors['G']} C={base_colors['C']}"
            stdscr.addstr(0, 0, "DNA SEQUENCER v3.2", curses.color_pair(6) | curses.A_BOLD)
            
            # contador de bases
            base_count = {base: 0 for base in dna_bases}
            for (x, y) in dna_pairs.keys():
                if y < sh:
                    # conta bases na tela atual (aproximação)
                    base_count[random.choice(dna_bases)] += 1
            
            count_str = " | ".join([f"{base}:{count}" for base, count in base_count.items()])
            if len(count_str) < sw - 20:
                stdscr.addstr(1, 0, count_str, curses.color_pair(5))
        except curses.error:
            pass

        # indicador de sequência especial
        if current_sequence:
            try:
                progress = min(100, (sequence_pos * 100) // len(current_sequence))
                seq_info = f"ANALYZING: {current_sequence} ({progress}%)"
                stdscr.addstr(sh-1, 0, seq_info[:sw], curses.color_pair(7))
            except curses.error:
                pass

        # legenda das cores
        try:
            legend = "A=Red T=Blue G=Green C=Yellow"
            stdscr.addstr(sh-2, sw - len(legend), legend, curses.color_pair(6))
        except curses.error:
            pass

        stdscr.refresh()
        time.sleep(0.05)

if __name__ == '__main__':
    try:
        import math
        curses.wrapper(main)
    except KeyboardInterrupt:
        pass