import streamlit as st import folium from streamlit_folium import folium_static import time import math import random # Wide mode st.set_page_config(layout="wide") # Deer hunting locations and resorts (approximated coordinates) deer_hunting_spots = [ ("Buffalo County, WI", 44.3661, -91.7535, "Big Buck Capital", "Trophy bucks, rugged terrain"), ("Winona County, MN", 44.0500, -91.6393, "Southeast MN", "Big bucks, public WMAs"), ("Houston County, MN", 43.6666, -91.4929, "Southeast MN", "Thriving herds, farmland"), ("Trempealeau County, WI", 44.3040, -91.3593, "Western WI", "Solid deer population"), ("Crawford County, WI", 43.2396, -90.9315, "Western WI", "Driftless Area, deer paradise"), ("Rutting Ridge Outfitters, WI", 44.4119, -91.8638, "Buffalo Co.", "Trophy hunts, rut focus"), ("Deer Haven Acres, WI", 43.8769, -89.4825, "Adams Co.", "238-acre preserve"), ("Nodak Lodge, MN", 47.5148, -94.8800, "Bena, MN", "Near Superior Nat’l Forest"), ("Wigwam Resort, MN", 48.6029, -93.4037, "Baudette, MN", "Northern woods, big deer"), ("Big River Resort, WI", 44.5896, -91.9988, "Alma, WI", "Chill vibes, near Rutting Ridge") ] # Initialize session state if 'hunter_position' not in st.session_state: st.session_state.hunter_position = [44.3661, -91.7535] # Start at Buffalo County if 'is_traveling' not in st.session_state: st.session_state.is_traveling = False if 'start' not in st.session_state: st.session_state.start = deer_hunting_spots[0] if 'destination' not in st.session_state: st.session_state.destination = deer_hunting_spots[1] if 'start_time' not in st.session_state: st.session_state.start_time = None if 'elapsed_time' not in st.session_state: st.session_state.elapsed_time = 0 if 'arrived' not in st.session_state: st.session_state.arrived = False if 'score' not in st.session_state: st.session_state.score = 0 if 'deer_remaining' not in st.session_state: st.session_state.deer_remaining = 0 # Distance calculation (Haversine in miles) def calculate_distance(lat1, lon1, lat2, lon2): R = 3958.8 lat1_rad, lon1_rad = math.radians(lat1), math.radians(lon1) lat2_rad, lon2_rad = math.radians(lat2), math.radians(lon2) dlat = lat2_rad - lat1_rad dlon = lon2_rad - lon1_rad a = math.sin(dlat / 2)**2 + math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(dlon / 2)**2 c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) return R * c # Create map def create_map(): m = folium.Map(location=st.session_state.hunter_position, zoom_start=8, tiles="CartoDB Positron") for spot in deer_hunting_spots: folium.Marker( location=[spot[1], spot[2]], popup=f'{spot[0]}
{spot[3]}
{spot[4]}', icon=folium.Icon(color='green', icon='tree', prefix='fa') ).add_to(m) folium.Marker( location=st.session_state.hunter_position, popup='Hunter’s Rig', icon=folium.Icon(color='blue', icon='truck', prefix='fa') ).add_to(m) return m # Move hunter's rig def move_rig(total_distance, step_time): target = [st.session_state.destination[1], st.session_state.destination[2]] current = st.session_state.hunter_position remaining_distance = calculate_distance(current[0], current[1], target[0], target[1]) speed = total_distance / 25.0 # miles per second (25s total travel) step_distance = speed * step_time total_lat_diff = target[0] - current[0] total_lon_diff = target[1] - current[1] total_hyp = math.sqrt(total_lat_diff**2 + total_lon_diff**2) if total_hyp > 0: lat_step = (total_lat_diff / total_hyp) * step_distance / (calculate_distance(current[0], current[1], current[0] + 0.01, current[1]) / 0.01) lon_step = (total_lon_diff / total_hyp) * step_distance / (calculate_distance(current[0], current[1], current[0], current[1] + 0.01) / 0.01) st.session_state.hunter_position[0] += lat_step st.session_state.hunter_position[1] += lon_step if remaining_distance < 0.1: st.session_state.hunter_position = target st.session_state.is_traveling = False st.session_state.arrived = True # Simple 3D hunting simulation (text-based for Streamlit) def hunt_deer(location): if st.session_state.deer_remaining == 0: st.session_state.deer_remaining = random.randint(3, 6) # Deer at location st.write(f"Hunting at {location[0]}: {st.session_state.deer_remaining} deer spotted.") action = st.radio("Choose your action:", ("Aim and Shoot", "Wait", "Move")) if action == "Aim and Shoot": if random.random() < 0.7: # 70% success rate st.session_state.score += 50 st.session_state.deer_remaining -= 1 st.success("🎯 Deer hunted! +50 points") else: st.warning("Missed the shot!") elif action == "Wait": st.write("You wait quietly... deer are still around.") elif action == "Move": st.session_state.deer_remaining -= random.randint(0, 2) # Some deer might flee st.write("You move, startling some deer.") if st.session_state.deer_remaining <= 0: st.write("No more deer in this area. Travel to another spot!") st.write(f"Score: {st.session_state.score}") # Layout left_col, right_col = st.columns([3, 1]) # Left column: Map and controls with left_col: st.markdown("### 🦌 Deer Hunter’s Basecamp 🌲") m = create_map() folium_static(m, width=1280, height=1024) col1, col2, col3 = st.columns(3) with col1: if st.button("🚚 Launch Rig"): st.session_state.is_traveling = True st.session_state.start_time = time.time() st.session_state.arrived = False with col2: if st.button("πŸ›‘ Stop Rig"): st.session_state.is_traveling = False st.session_state.start_time = None with col3: if st.button("πŸ”„ Reset to Start"): st.session_state.hunter_position = [st.session_state.start[1], st.session_state.start[2]] st.session_state.is_traveling = False st.session_state.start_time = None st.session_state.elapsed_time = 0 st.session_state.arrived = False st.session_state.deer_remaining = 0 st.rerun() if st.session_state.arrived: st.success(f"🎯 Arrived at {st.session_state.destination[0]}!") hunt_deer(st.session_state.destination) # Right column: Stats and navigation with right_col: st.markdown("### πŸ“‘ Hunt Status") total_distance = calculate_distance(st.session_state.start[1], st.session_state.start[2], st.session_state.destination[1], st.session_state.destination[2]) remaining_distance = calculate_distance(st.session_state.hunter_position[0], st.session_state.hunter_position[1], st.session_state.destination[1], st.session_state.destination[2]) speed = total_distance / (25.0 / 3600) # mph st.write(f"**Start**: {st.session_state.start[0]}") st.write(f"**Destination**: {st.session_state.destination[0]}") st.write(f"**Total Distance**: {total_distance:.1f} miles") st.write(f"**Remaining**: {remaining_distance:.1f} miles") st.write(f"**Speed**: {speed:.1f} mph") st.write(f"**ETA**: 25.0 seconds") st.write(f"**Score**: {st.session_state.score}") start_col, dest_col = st.columns(2) with start_col: st.write("**🚦 Start Points**") for spot in deer_hunting_spots: if st.button(f"πŸ“ {spot[0]}", key=f"start_{spot[0]}"): st.session_state.start = spot st.session_state.hunter_position = [spot[1], spot[2]] st.session_state.is_traveling = False st.session_state.arrived = False st.session_state.deer_remaining = 0 st.rerun() with dest_col: st.write("**🏁 Destinations**") for spot in deer_hunting_spots: if st.button(f"🎯 {spot[0]}", key=f"dest_{spot[0]}"): st.session_state.destination = spot st.session_state.is_traveling = False st.session_state.arrived = False st.session_state.deer_remaining = 0 st.rerun() # Movement logic if st.session_state.is_traveling: move_rig(total_distance, 0.5) if st.session_state.start_time: st.session_state.elapsed_time = time.time() - st.session_state.start_time time.sleep(0.5) st.rerun()