Spaces:
Running
Running
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'<b>{spot[0]}</b><br>{spot[3]}<br>{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() |