# -*- coding: utf-8 -*-
# ================================================================
# KEVIN VILLA BTC PUZZLE 7.1 BTC - V15 (ULTIMATE EDITION)
# Récord Guardado | Anti-Crash de Salida | Minería Real | 1 Portal
# ================================================================
import ui, hashlib, os, time, random, math, sound, console, threading
from ecdsa import SigningKey, SECP256k1
console.set_idle_timer_disabled(True)
# ================= RANGO PUZZLE Y CRIPTO =================
MIN_K = 0x400000000000000000
MAX_K = 0x7fffffffffffffffff
RANGE_SIZE = MAX_K - MIN_K + 1
TARGET_ADDR = "1PWo3JeB9jrGwfHDNpdGK54CRas7fsVzXU"
B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def b58enc(v):
n = int.from_bytes(v, 'big')
r = ''
while n > 0:
n, mod = divmod(n, 58)
r = B58[mod] + r
for b in v:
if b == 0: r = '1' + r
else: break
return r
def get_h160(addr):
n = 0
for c in addr: n = n * 58 + B58.index(c)
return n.to_bytes(25, 'big')[1:21]
TARGET_H160 = get_h160(TARGET_ADDR)
def priv_to_address(priv_int):
try:
pb = priv_int.to_bytes(32, 'big')
sk = SigningKey.from_string(pb, curve=SECP256k1)
vk = sk.verifying_key
x = vk.to_string()[:32]
y = vk.to_string()[32:]
prefix = b'\x02' if int.from_bytes(y, 'big') % 2 == 0 else b'\x03'
pub = prefix + x
sha = hashlib.sha256(pub).digest()
ripe = hashlib.new('ripemd160', sha).digest()
payload = b'\x00' + ripe
cs = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
return b58enc(payload + cs), pub.hex()
except Exception:
return "ERROR", "ERROR"
# ================= COLORES =================
BLACK = '#050505'
GRAY_BG = '#0d0d12'
GRID_C = '#181822'
GREEN_F = '#00ff41'
GOLD = '#ffd700'
BLUE_BTC = '#0088ff'
RED = '#ff3333'
CYAN = '#00ffff'
PURPLE = '#aa00ff'
WHITE = '#ffffff'
def get_rgba(hex_color, alpha):
h = hex_color.lstrip('#')
r, g, b = tuple(int(h[i:i+2], 16) for i in (0, 2, 4))
return (r/255.0, g/255.0, b/255.0, alpha)
# ================= CLASES DEL JUEGO =================
class GameCanvas(ui.View):
def draw(self):
if hasattr(self, 'game_engine') and self.game_engine:
self.game_engine.render_frame()
class SnakeGameV15(ui.View):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.background_color = BLACK
self.touch_enabled = True
self._swipe_start = None
self.is_running = True # Interruptor maestro para evitar zombis en memoria
# Cargar Récord Guardado
self.high_score = 0.0
self._load_high_score()
sw, sh = ui.get_screen_size()
self.is_portrait = sw < sh
safe_top = 40
hud_height = 100
canvas_y = safe_top + hud_height + 5
avail_h = sh - canvas_y
self.CELL = 20 if self.is_portrait else 18
self.COLS = int(sw / self.CELL)
self.ROWS = int(avail_h / self.CELL)
self.W = self.COLS * self.CELL
self.H = self.ROWS * self.CELL
self._build_ui(sw, sh, safe_top, hud_height, canvas_y)
self.mining_active = False
self.new_game()
def _load_high_score(self):
try:
with open('btc_record.txt', 'r') as f:
self.high_score = float(f.read().strip())
except:
self.high_score = 0.0
def _save_high_score(self):
if self.score > self.high_score:
self.high_score = self.score
try:
with open('btc_record.txt', 'w') as f:
f.write(str(self.high_score))
except: pass
def _build_ui(self, sw, sh, safe_top, hud_h, canvas_y):
self.hud_panel = ui.View(frame=(5, safe_top, sw-10, hud_h))
self.hud_panel.background_color = '#0a0a10'
self.hud_panel.border_color = GREEN_F
self.hud_panel.border_width = 1
self.hud_panel.corner_radius = 8
self.hud_panel.touch_enabled = False
self.add_subview(self.hud_panel)
self.lbl_stats = ui.Label(frame=(10, 5, self.hud_panel.width-20, 25))
self.lbl_stats.font = ('Courier-Bold', 12)
self.lbl_stats.text_color = GREEN_F
self.hud_panel.add_subview(self.lbl_stats)
self.lbl_crypto = ui.Label(frame=(10, 35, self.hud_panel.width-20, hud_h-40))
self.lbl_crypto.font = ('Courier', 11)
self.lbl_crypto.text_color = GOLD
self.lbl_crypto.number_of_lines = 0
self.hud_panel.add_subview(self.lbl_crypto)
cx = (sw - self.W) / 2
self.canvas = GameCanvas(frame=(cx, canvas_y, self.W, self.H))
self.canvas.background_color = GRAY_BG
self.canvas.border_color = '#222'
self.canvas.border_width = 2
self.canvas.game_engine = self
self.canvas.touch_enabled = False
self.add_subview(self.canvas)
def new_game(self):
cx, cy = self.COLS // 2, self.ROWS // 2
self.snake = [{'x': cx, 'y': cy}, {'x': cx-1, 'y': cy}, {'x': cx-2, 'y': cy}]
self.direction = {'x': 1, 'y': 0}
self.next_dir = {'x': 1, 'y': 0}
self.is_behind = False
self.score = 0.0
self.current_fps = 5.0
self.portal = {'x': -1, 'y': -1}
self.portal = self._spawn_portal()
self.coin = self._spawn_coin()
self.blue_coin = None
self.last_blue_time = time.time()
self.game_over = False
self.game_won = False
self.keys_checked = 0
self.start_time = time.time()
self.live_miner_priv = "INICIANDO MOTOR SECP256k1..."
self.live_miner_addr = ""
self.anim_time = 0.0
if not self.mining_active and self.is_running:
ui.delay(self._start_mining_thread, 1.0)
self._tick()
def _start_mining_thread(self):
if not getattr(self, 'is_running', False): return
self.mining_active = True
threading.Thread(target=self._background_miner, daemon=True).start()
def _background_miner(self):
while self.mining_active and getattr(self, 'is_running', False):
if self.game_over or self.game_won:
time.sleep(0.5)
continue
for _ in range(2):
k = random.randint(MIN_K, MAX_K)
addr, _ = priv_to_address(k)
self.live_miner_priv = hex(k)
self.live_miner_addr = addr
self.keys_checked += 1
try:
if get_h160(addr) == TARGET_H160:
self.coin = {'priv': k, 'addr': addr}
self._trigger_win()
return
except: pass
time.sleep(0.01)
def _spawn_coin(self, is_special=False):
while True:
rx, ry = random.randint(0, self.COLS-1), random.randint(0, self.ROWS-1)
in_snake = any(s['x'] == rx and s['y'] == ry for s in self.snake)
in_portal = (rx == self.portal['x'] and ry == self.portal['y'])
if not in_snake and not in_portal:
layer = random.choice([True, False])
if is_special:
return {'x': rx, 'y': ry, 'is_behind': layer, 'spawn_time': time.time(), 'anim': random.random()*10}
else:
k = random.randint(MIN_K, MAX_K)
addr, _ = priv_to_address(k)
return {'x': rx, 'y': ry, 'priv': k, 'addr': addr, 'is_behind': layer, 'anim': random.random()*10}
def _spawn_portal(self):
while True:
rx, ry = random.randint(1, self.COLS-2), random.randint(1, self.ROWS-2)
in_snake = any(s['x'] == rx and s['y'] == ry for s in self.snake)
if not in_snake:
return {'x': rx, 'y': ry, 'color': PURPLE}
def _move_coin(self, c_dict):
moves = [{'x': 0, 'y': 1}, {'x': 0, 'y': -1}, {'x': 1, 'y': 0}, {'x': -1, 'y': 0}]
random.shuffle(moves)
for m in moves:
cx = (c_dict['x'] + m['x']) % self.COLS
cy = (c_dict['y'] + m['y']) % self.ROWS
in_snake = any(s['x'] == cx and s['y'] == cy for s in self.snake)
in_portal = (self.portal['x'] == cx and self.portal['y'] == cy)
if not in_snake and not in_portal:
c_dict['x'] = cx
c_dict['y'] = cy
break
def _trigger_win(self):
self.game_won = True
self.mining_active = False
self._save_high_score()
try:
with open('WINNER.txt', 'a') as f:
f.write(f"=== ¡PUZZLE RESUELTO! ===\nPRIV: {hex(self.coin['priv'])}\nADDR: {self.coin['addr']}\n")
except: pass
try:
sound.play_effect('arcade:Coin_4')
ui.delay(lambda: sound.play_effect('arcade:Coin_5'), 0.2)
ui.delay(lambda: sound.play_effect('arcade:Powerup_1'), 0.4)
ui.delay(lambda: sound.play_effect('arcade:Jump_1'), 0.6)
except: pass
self.canvas.set_needs_display()
self._update_hud()
def _tick(self):
if not getattr(self, 'is_running', False): return # Anti-Zombie Loop
if self.game_over or self.game_won: return
self._update_logic()
self.canvas.set_needs_display()
self._update_hud()
if getattr(self, 'is_running', False):
ui.delay(self._tick, 1.0 / self.current_fps)
def _update_logic(self):
self.anim_time += 0.2
self.direction = {'x': self.next_dir['x'], 'y': self.next_dir['y']}
current_time = time.time()
# Gestionar Temporizadores del BTC Azul (15 SEGUNDOS)
if not self.blue_coin and current_time - self.last_blue_time > 30:
self.blue_coin = self._spawn_coin(is_special=True)
sound.play_effect('arcade:Jump_2')
elif self.blue_coin and current_time - self.blue_coin['spawn_time'] > 15:
self.blue_coin = None
self.last_blue_time = current_time
# Mover Gusano
head = self.snake[0]
nx = (head['x'] + self.direction['x']) % self.COLS
ny = (head['y'] + self.direction['y']) % self.ROWS
new_head = {'x': nx, 'y': ny}
# Choque y Game Over
for segment in self.snake[1:]:
if new_head['x'] == segment['x'] and new_head['y'] == segment['y']:
self.game_over = True
self._save_high_score()
sound.play_effect('arcade:Explosion_1')
return
self.snake.insert(0, new_head)
# Comer Lógica
ate_yellow = (new_head['x'] == self.coin['x'] and new_head['y'] == self.coin['y'] and self.is_behind == self.coin['is_behind'])
ate_blue = self.blue_coin and (new_head['x'] == self.blue_coin['x'] and new_head['y'] == self.blue_coin['y'] and self.is_behind == self.blue_coin['is_behind'])
if ate_yellow:
self.score += 0.00001
if self.score > self.high_score:
self.high_score = self.score # Sube el récord en vivo
try:
if get_h160(self.coin['addr']) == TARGET_H160:
self._trigger_win()
return
except: pass
sound.play_effect('arcade:Coin_2')
self.current_fps = min(22.0, self.current_fps + 1.0)
self.coin = self._spawn_coin()
elif ate_blue:
sound.play_effect('arcade:Jump_3')
for _ in range(2):
if len(self.snake) > 3:
self.snake.pop()
self.current_fps = max(4.0, self.current_fps - 3.0)
self.blue_coin = None
self.last_blue_time = current_time
else:
self.snake.pop()
if random.random() < 0.2:
self._move_coin(self.coin)
if self.blue_coin and random.random() < 0.2:
self._move_coin(self.blue_coin)
# Atravesar Portal Único
if new_head['x'] == self.portal['x'] and new_head['y'] == self.portal['y']:
self.is_behind = not self.is_behind
sound.play_effect('arcade:Powerup_1')
self.portal = self._spawn_portal()
def _update_hud(self):
elapsed = time.time() - self.start_time
kps = self.keys_checked / max(elapsed, 1)
layer_text = "DIM: OSCURA" if self.is_behind else "DIM: SUPERFICIE"
self.lbl_stats.text = f"₿ {self.score:.5f} (MAX: {self.high_score:.5f}) | {kps:.1f}k/s | {layer_text}"
c_text = f"🎯 TARGET : {TARGET_ADDR[:22]}...\n"
c_text += f"⚙️ M_PRIV : {self.live_miner_priv[:26]}...\n"
c_text += f"💼 M_ADDR : {self.live_miner_addr}"
if self.game_won:
self.lbl_crypto.text_color = GREEN_F
c_text = "🏆 ¡PUZZLE RESUELTO! CLAVE ENCONTRADA 🏆"
elif self.game_over:
c_text = "💀 GAME OVER 💀"
self.lbl_crypto.text_color = RED
else:
self.lbl_crypto.text_color = CYAN
self.lbl_crypto.text = c_text
def touch_began(self, touch):
if self.game_won: return
if self.game_over:
self.new_game()
return
self._swipe_start = touch.location
def touch_ended(self, touch):
if self.game_won or self.game_over or not self._swipe_start: return
dx_move = touch.location[0] - self._swipe_start[0]
dy_move = touch.location[1] - self._swipe_start[1]
if abs(dx_move) < 15 and abs(dy_move) < 15:
hx_screen = self.canvas.x + self.snake[0]['x'] * self.CELL + (self.CELL / 2)
hy_screen = self.canvas.y + self.snake[0]['y'] * self.CELL + (self.CELL / 2)
dx_tap = touch.location[0] - hx_screen
dy_tap = touch.location[1] - hy_screen
if self.direction['x'] != 0:
new_dir = {'x': 0, 'y': -1 if dy_tap < 0 else 1}
else:
new_dir = {'x': -1 if dx_tap < 0 else 1, 'y': 0}
else:
if abs(dx_move) > abs(dy_move):
new_dir = {'x': 1 if dx_move > 0 else -1, 'y': 0}
else:
new_dir = {'x': 0, 'y': 1 if dy_move > 0 else -1}
if not (new_dir['x'] == -self.direction['x'] and new_dir['y'] == -self.direction['y']):
self.next_dir = new_dir
self._swipe_start = None
def render_frame(self):
if not getattr(self, 'is_running', False): return # Anti-Zombie Draw
try:
ui.set_color(GRAY_BG)
ui.fill_rect(0, 0, self.W, self.H)
ui.set_color(GRID_C)
for x in range(0, self.W, self.CELL): ui.fill_rect(x, 0, 1, self.H)
for y in range(0, self.H, self.CELL): ui.fill_rect(0, y, self.W, 1)
if self.is_behind and not self.game_won:
self._draw_snake(color_head='#555555', color_body='#2a2a2a')
ui.set_color('rgba(0, 0, 0, 0.6)')
ui.fill_rect(0, 0, self.W, self.H)
ui.set_color('rgba(30, 30, 45, 0.4)')
for x in range(0, self.W, self.CELL): ui.fill_rect(x, 0, 1, self.H)
for y in range(0, self.H, self.CELL): ui.fill_rect(0, y, self.W, 1)
cx, cy = self.portal['x']*self.CELL + self.CELL//2, self.portal['y']*self.CELL + self.CELL//2
r = int(self.CELL * 0.7)
ui.set_color(get_rgba(self.portal['color'], 0.4))
ui.Path.oval(cx-r, cy-r, r*2, r*2).fill()
path = ui.Path.oval(cx-r, cy-r, r*2, r*2)
path.line_width = 2
path.set_line_dash([4, 6], (self.anim_time * 10) % 10)
ui.set_color(self.portal['color'])
path.stroke()
def draw_btc(c_data, hex_color):
cx, cy = c_data['x']*self.CELL + self.CELL//2, c_data['y']*self.CELL + self.CELL//2
r = int(self.CELL * 0.4 + math.sin(self.anim_time + c_data['anim'])*1.5)
alpha = 1.0 if c_data['is_behind'] == self.is_behind else 0.2
ui.set_color(get_rgba(hex_color, alpha * 0.4))
ui.Path.oval(cx-int(r*1.5), cy-int(r*1.5), int(r*3), int(r*3)).fill()
ui.set_color(get_rgba(hex_color, alpha))
ui.Path.oval(cx-r, cy-r, r*2, r*2).fill()
ui.draw_string('₿', rect=(cx-r, cy-r, r*2, r*2), font=('Arial-Bold', int(r*1.5)), color=get_rgba(BLACK, alpha), alignment=ui.ALIGN_CENTER)
if not self.game_won and not self.game_over:
draw_btc(self.coin, GOLD)
if self.blue_coin:
draw_btc(self.blue_coin, BLUE_BTC)
if not self.game_won and not self.game_over:
if self.is_behind: self._draw_snake(color_head='#555555', color_body='#2a2a2a')
else: self._draw_snake(color_head=WHITE, color_body=GREEN_F)
if self.game_over:
ui.set_color('rgba(30, 0, 0, 0.85)')
ui.fill_rect(0, 0, self.W, self.H)
ui.draw_string('💀 GAME OVER 💀', rect=(0, self.H/2 - 60, self.W, 40), font=('Courier-Bold', 26), color=RED, alignment=ui.ALIGN_CENTER)
ui.draw_string(f'SCORE FINAL: ₿ {self.score:.5f}', rect=(0, self.H/2 - 10, self.W, 40), font=('Courier-Bold', 20), color=GOLD, alignment=ui.ALIGN_CENTER)
ui.draw_string(f'RÉCORD: ₿ {self.high_score:.5f}', rect=(0, self.H/2 + 20, self.W, 30), font=('Courier-Bold', 14), color=CYAN, alignment=ui.ALIGN_CENTER)
ui.draw_string('TOCA LA PANTALLA PARA REINICIAR', rect=(0, self.H/2 + 60, self.W, 30), font=('Arial-Bold', 14), color=WHITE, alignment=ui.ALIGN_CENTER)
if self.game_won:
ui.set_color('rgba(0, 0, 0, 0.85)')
ui.fill_rect(0, 0, self.W, self.H)
ui.draw_string('🏁 🏆 ¡LO LOGRASTE! 🏆 🏁', rect=(0, self.H/2 - 80, self.W, 40), font=('Courier-Bold', 22), color=GOLD, alignment=ui.ALIGN_CENTER)
ui.draw_string('¡COLISIÓN CRIPTOGRÁFICA ENCONTRADA!', rect=(0, self.H/2 - 40, self.W, 30), font=('Arial-Bold', 14), color=GREEN_F, alignment=ui.ALIGN_CENTER)
ui.draw_string(f'PRIV:\n{hex(self.coin["priv"])}', rect=(10, self.H/2 + 10, self.W-20, 50), font=('Courier-Bold', 12), color=WHITE, alignment=ui.ALIGN_CENTER)
ui.draw_string(f'ADDR:\n{self.coin["addr"]}', rect=(10, self.H/2 + 70, self.W-20, 50), font=('Courier-Bold', 12), color=CYAN, alignment=ui.ALIGN_CENTER)
except Exception as e:
pass
def _draw_snake(self, color_head, color_body):
for i, segment in enumerate(self.snake):
px, py = int(segment['x'] * self.CELL), int(segment['y'] * self.CELL)
pad = 2
if i == 0:
ui.set_color(color_head)
ui.Path.rounded_rect(px+1, py+1, self.CELL-2, self.CELL-2, 4).fill()
ui.set_color(BLACK)
dx, dy = self.direction['x'], self.direction['y']
sz = max(2, self.CELL//6)
if dx == 1: ex1, ey1, ex2, ey2 = px+self.CELL-4, py+4, px+self.CELL-4, py+self.CELL-6
elif dx == -1:ex1, ey1, ex2, ey2 = px+2, py+4, px+2, py+self.CELL-6
elif dy == -1:ex1, ey1, ex2, ey2 = px+4, py+2, px+self.CELL-6, py+2
else: ex1, ey1, ex2, ey2 = px+4, py+self.CELL-4, px+self.CELL-6, py+self.CELL-4
ui.Path.oval(ex1, ey1, sz, sz).fill()
ui.Path.oval(ex2, ey2, sz, sz).fill()
else:
alpha = max(0.4, 1.0 - (i / len(self.snake)))
ui.set_color(get_rgba(color_body, alpha))
ui.Path.rounded_rect(px+pad, py+pad, max(1, self.CELL-pad*2), max(1, self.CELL-pad*2), 2).fill()
def will_close(self):
"""Destrucción total del entorno para evitar crashes de memoria"""
self.is_running = False
self.game_over = True
self.mining_active = False
if __name__ == "__main__":
app = SnakeGameV15()
app.present('full_screen', hide_title_bar=True)