File size: 8,586 Bytes
114d71b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60c9ae1
114d71b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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()