mirror of
https://github.com/System-End/haxmas-day-8.git
synced 2026-04-19 15:28:18 +00:00
init
This commit is contained in:
parent
1ce576fb39
commit
096145cf2e
1 changed files with 431 additions and 0 deletions
431
main.py
Normal file
431
main.py
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
import re
|
||||
import tkinter as tk
|
||||
from datetime import datetime
|
||||
from tkinter import messagebox, ttk
|
||||
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.options import Options as ChromeOptions
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.edge.options import Options as EdgeOptions
|
||||
from selenium.webdriver.firefox.options import Options as FirefoxOptions
|
||||
|
||||
|
||||
def detect_and_create_driver():
|
||||
browsers = [
|
||||
("Chrome", create_chrome_driver),
|
||||
("Firefox", create_firefox_driver),
|
||||
("Edge", create_edge_driver),
|
||||
]
|
||||
for browser_name, create_func in browsers:
|
||||
try:
|
||||
return create_func(), browser_name
|
||||
except Exception:
|
||||
continue
|
||||
return None, None
|
||||
|
||||
|
||||
def create_chrome_driver():
|
||||
options = ChromeOptions()
|
||||
options.add_argument("--disable-extensions")
|
||||
options.add_argument("--disable-gpu")
|
||||
options.add_argument("--no-sandbox")
|
||||
options.add_argument("--disable-dev-shm-usage")
|
||||
options.page_load_strategy = "eager"
|
||||
options.add_experimental_option(
|
||||
"excludeSwitches", ["enable-logging", "enable-automation"]
|
||||
)
|
||||
return webdriver.Chrome(options=options)
|
||||
|
||||
|
||||
def create_firefox_driver():
|
||||
options = FirefoxOptions()
|
||||
options.set_preference("dom.webnotifications.enabled", False)
|
||||
options.page_load_strategy = "eager"
|
||||
return webdriver.Firefox(options=options)
|
||||
|
||||
|
||||
def create_edge_driver():
|
||||
options = EdgeOptions()
|
||||
options.add_argument("--disable-extensions")
|
||||
options.add_argument("--disable-gpu")
|
||||
options.page_load_strategy = "eager"
|
||||
return webdriver.Edge(options=options)
|
||||
|
||||
|
||||
def parse_number(text):
|
||||
text = text.lower().replace(",", "").strip()
|
||||
multipliers = {
|
||||
"million": 1e6,
|
||||
"billion": 1e9,
|
||||
"trillion": 1e12,
|
||||
"quadrillion": 1e15,
|
||||
"quintillion": 1e18,
|
||||
}
|
||||
for word, mult in multipliers.items():
|
||||
if word in text:
|
||||
return float(text.replace(word, "").strip()) * mult
|
||||
try:
|
||||
return float(text)
|
||||
except:
|
||||
return 0
|
||||
|
||||
|
||||
class Bot:
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.running = False
|
||||
self.clicks = 0
|
||||
self.start_time = None
|
||||
self.cookie = None
|
||||
self.cycle = 0
|
||||
self.last_cps = 0
|
||||
self.buildings_bought = 0
|
||||
self.upgrades_bought = 0
|
||||
|
||||
def load(self):
|
||||
self.driver.get("https://ozh.github.io/cookieclicker/")
|
||||
|
||||
def ready(self):
|
||||
try:
|
||||
c = self.driver.find_element(By.ID, "bigCookie")
|
||||
if c.size["width"] > 0:
|
||||
self.cookie = c
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
def start(self):
|
||||
self.start_time = datetime.now()
|
||||
self.running = True
|
||||
|
||||
def click(self, times):
|
||||
for _ in range(times):
|
||||
try:
|
||||
self.cookie.click()
|
||||
self.clicks += 1
|
||||
except Exception:
|
||||
try:
|
||||
self.cookie = self.driver.find_element(By.ID, "bigCookie")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def golden(self):
|
||||
try:
|
||||
shimmers = self.driver.find_elements(By.CLASS_NAME, "shimmer")
|
||||
for s in shimmers:
|
||||
try:
|
||||
s.click()
|
||||
except:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def get_building_info(self):
|
||||
try:
|
||||
products = self.driver.find_elements(By.CSS_SELECTOR, ".product.unlocked")
|
||||
info = []
|
||||
for p in products:
|
||||
try:
|
||||
enabled = "enabled" in p.get_attribute("class")
|
||||
price_el = p.find_element(By.CLASS_NAME, "price")
|
||||
price_text = price_el.text
|
||||
price = parse_number(price_text)
|
||||
info.append({"element": p, "price": price, "enabled": enabled})
|
||||
except:
|
||||
continue
|
||||
return info
|
||||
except:
|
||||
return []
|
||||
|
||||
def buy_smart(self, remaining_time):
|
||||
if remaining_time < 15:
|
||||
return
|
||||
|
||||
buildings = self.get_building_info()
|
||||
current_cps = self.get_cps_number()
|
||||
cookies = self.get_cookies()
|
||||
|
||||
for b in buildings:
|
||||
if not b["enabled"]:
|
||||
continue
|
||||
price = b["price"]
|
||||
if price <= 0:
|
||||
continue
|
||||
|
||||
estimated_cps_gain = max(current_cps * 0.1, 1)
|
||||
|
||||
if current_cps > 0:
|
||||
breakeven = price / estimated_cps_gain
|
||||
else:
|
||||
breakeven = 5
|
||||
|
||||
if remaining_time > 25:
|
||||
if price < cookies * 0.8:
|
||||
try:
|
||||
b["element"].click()
|
||||
self.buildings_bought += 1
|
||||
except:
|
||||
pass
|
||||
break
|
||||
elif remaining_time > 20:
|
||||
if breakeven < remaining_time * 0.5:
|
||||
try:
|
||||
b["element"].click()
|
||||
self.buildings_bought += 1
|
||||
except:
|
||||
pass
|
||||
break
|
||||
|
||||
def upgrade(self):
|
||||
try:
|
||||
upgrades = self.driver.find_elements(
|
||||
By.CSS_SELECTOR, "#upgrades .upgrade.enabled"
|
||||
)
|
||||
for u in upgrades[:2]:
|
||||
try:
|
||||
u.click()
|
||||
self.upgrades_bought += 1
|
||||
except:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def buy_cheapest(self, count=1):
|
||||
try:
|
||||
for _ in range(count):
|
||||
products = self.driver.find_elements(
|
||||
By.CSS_SELECTOR, ".product.unlocked.enabled"
|
||||
)
|
||||
if products:
|
||||
products[0].click()
|
||||
self.buildings_bought += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def get_cookies(self):
|
||||
try:
|
||||
text = self.driver.find_element(By.ID, "cookies").text.split("\n")[0]
|
||||
text = text.replace("cookies", "").strip()
|
||||
return parse_number(text)
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
def get_cps_number(self):
|
||||
try:
|
||||
text = self.driver.find_element(By.ID, "cookies").text
|
||||
if "per second" in text:
|
||||
cps_text = text.split("per second:")[-1].strip()
|
||||
self.last_cps = parse_number(cps_text)
|
||||
return self.last_cps
|
||||
return self.last_cps
|
||||
except Exception:
|
||||
return self.last_cps
|
||||
|
||||
def get_cps(self):
|
||||
try:
|
||||
text = self.driver.find_element(By.ID, "cookies").text
|
||||
if "per second" in text:
|
||||
return text.split("per second:")[-1].strip()
|
||||
return "0"
|
||||
except Exception:
|
||||
return "0"
|
||||
|
||||
def elapsed(self):
|
||||
if self.start_time:
|
||||
return (datetime.now() - self.start_time).total_seconds()
|
||||
return 0
|
||||
|
||||
def remaining(self):
|
||||
return max(0, 60 - self.elapsed())
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self.driver.quit()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class GUI:
|
||||
def __init__(self):
|
||||
self.root = tk.Tk()
|
||||
self.root.title("Cookie Speedrun Bot")
|
||||
self.root.geometry("500x600")
|
||||
self.bot = None
|
||||
self.comp = True
|
||||
self.build()
|
||||
|
||||
def build(self):
|
||||
ttk.Label(
|
||||
self.root, text="COOKIE SPEEDRUN BOT", font=("Arial", 22, "bold")
|
||||
).pack(pady=20)
|
||||
|
||||
f1 = ttk.Frame(self.root)
|
||||
f1.pack(pady=10)
|
||||
self.mode = tk.StringVar(value="COMP")
|
||||
ttk.Radiobutton(f1, text="Practice", variable=self.mode, value="PRACTICE").pack(
|
||||
side="left", padx=20
|
||||
)
|
||||
ttk.Radiobutton(f1, text="COMPETITION", variable=self.mode, value="COMP").pack(
|
||||
side="left", padx=20
|
||||
)
|
||||
|
||||
f2 = ttk.Frame(self.root)
|
||||
f2.pack(pady=10)
|
||||
self.start_btn = ttk.Button(f2, text="START", command=self.start_bot)
|
||||
self.start_btn.pack(side="left", padx=10)
|
||||
self.stop_btn = ttk.Button(
|
||||
f2, text="STOP", command=self.stop_bot, state="disabled"
|
||||
)
|
||||
self.stop_btn.pack(side="left", padx=10)
|
||||
|
||||
self.timer = tk.StringVar(value="60")
|
||||
ttk.Label(
|
||||
self.root,
|
||||
textvariable=self.timer,
|
||||
font=("Arial", 72, "bold"),
|
||||
foreground="red",
|
||||
).pack(pady=20)
|
||||
|
||||
self.phase = tk.StringVar(value="---")
|
||||
ttk.Label(
|
||||
self.root,
|
||||
textvariable=self.phase,
|
||||
font=("Arial", 16, "bold"),
|
||||
foreground="blue",
|
||||
).pack()
|
||||
|
||||
ttk.Separator(self.root).pack(fill="x", pady=20)
|
||||
|
||||
self.result = tk.StringVar(value="---")
|
||||
ttk.Label(self.root, text="FINAL COOKIES:", font=("Arial", 14)).pack()
|
||||
ttk.Label(
|
||||
self.root,
|
||||
textvariable=self.result,
|
||||
font=("Arial", 32, "bold"),
|
||||
foreground="green",
|
||||
).pack(pady=5)
|
||||
|
||||
self.cps_var = tk.StringVar(value="CPS: ---")
|
||||
ttk.Label(self.root, textvariable=self.cps_var, font=("Arial", 14)).pack()
|
||||
|
||||
self.clicks_var = tk.StringVar(value="Clicks: ---")
|
||||
ttk.Label(self.root, textvariable=self.clicks_var, font=("Arial", 14)).pack()
|
||||
|
||||
self.buildings_var = tk.StringVar(value="Buildings: --- | Upgrades: ---")
|
||||
ttk.Label(self.root, textvariable=self.buildings_var, font=("Arial", 10)).pack()
|
||||
|
||||
self.status = tk.StringVar(value="Click START")
|
||||
ttk.Label(self.root, textvariable=self.status, font=("Arial", 10)).pack(pady=20)
|
||||
|
||||
def start_bot(self):
|
||||
self.status.set("Starting browser...")
|
||||
self.root.update()
|
||||
driver, browser = detect_and_create_driver()
|
||||
if not driver:
|
||||
messagebox.showerror("Error", "No browser!")
|
||||
return
|
||||
self.status.set(f"{browser} - PICK LANGUAGE!")
|
||||
self.comp = self.mode.get() == "COMP"
|
||||
self.bot = Bot(driver)
|
||||
self.start_btn.config(state="disabled")
|
||||
self.stop_btn.config(state="normal")
|
||||
self.result.set("---")
|
||||
self.cps_var.set("CPS: ---")
|
||||
self.clicks_var.set("Clicks: ---")
|
||||
self.buildings_var.set("Buildings: --- | Upgrades: ---")
|
||||
self.timer.set("--")
|
||||
self.phase.set("PICK LANGUAGE")
|
||||
self.bot.load()
|
||||
self.wait()
|
||||
|
||||
def wait(self):
|
||||
if not self.bot:
|
||||
return
|
||||
if self.bot.ready():
|
||||
self.bot.start()
|
||||
self.status.set("GO!")
|
||||
self.loop()
|
||||
else:
|
||||
self.root.after(50, self.wait)
|
||||
|
||||
def loop(self):
|
||||
if not self.bot or not self.bot.running:
|
||||
return
|
||||
|
||||
sec = self.bot.elapsed()
|
||||
remaining = self.bot.remaining()
|
||||
self.bot.cycle += 1
|
||||
|
||||
if self.bot.cycle % 10 == 0:
|
||||
left = max(0, 60 - sec)
|
||||
self.timer.set(f"{int(left)}" if self.comp else f"{int(sec)}")
|
||||
self.cps_var.set(f"CPS: {self.bot.get_cps()}")
|
||||
self.buildings_var.set(
|
||||
f"Buildings: {self.bot.buildings_bought} | Upgrades: {self.bot.upgrades_bought}"
|
||||
)
|
||||
|
||||
if self.comp and sec >= 60:
|
||||
final = self.bot.get_cookies()
|
||||
cps = self.bot.get_cps()
|
||||
clicks = self.bot.clicks
|
||||
self.result.set(f"{final:,.0f}")
|
||||
self.cps_var.set(f"CPS: {cps}")
|
||||
self.clicks_var.set(f"Clicks: {clicks:,}")
|
||||
self.timer.set("0")
|
||||
self.phase.set("DONE!")
|
||||
self.status.set("Competition finished!")
|
||||
self.bot.stop()
|
||||
self.start_btn.config(state="normal")
|
||||
self.stop_btn.config(state="disabled")
|
||||
return
|
||||
|
||||
if remaining > 45:
|
||||
self.bot.click(300)
|
||||
self.bot.golden()
|
||||
self.bot.upgrade()
|
||||
self.bot.buy_cheapest(3)
|
||||
self.phase.set("PHASE 1: RUSH BUILD")
|
||||
elif remaining > 25:
|
||||
self.bot.click(300)
|
||||
self.bot.golden()
|
||||
self.bot.upgrade()
|
||||
self.bot.buy_smart(remaining)
|
||||
self.phase.set("PHASE 2: SMART BUY")
|
||||
# elif remaining > 15:
|
||||
# self.bot.click(100)
|
||||
# self.bot.golden()
|
||||
# self.bot.upgrade()
|
||||
# self.phase.set("PHASE 3: UPGRADES ONLY")
|
||||
else:
|
||||
self.bot.click(600)
|
||||
self.bot.golden()
|
||||
self.phase.set("PHASE 3: ACCUMULATE")
|
||||
|
||||
self.root.after(1, self.loop)
|
||||
|
||||
def stop_bot(self):
|
||||
if self.bot:
|
||||
self.bot.stop()
|
||||
self.bot.close()
|
||||
self.bot = None
|
||||
self.status.set("Stopped")
|
||||
self.timer.set("--")
|
||||
self.start_btn.config(state="normal")
|
||||
self.stop_btn.config(state="disabled")
|
||||
|
||||
def close(self):
|
||||
if self.bot:
|
||||
self.bot.close()
|
||||
self.root.destroy()
|
||||
|
||||
def run(self):
|
||||
self.root.protocol("WM_DELETE_WINDOW", self.close)
|
||||
self.root.mainloop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
GUI().run()
|
||||
Loading…
Add table
Reference in a new issue