File size: 4,004 Bytes
36c1c11
 
 
25a06ca
edf6b35
 
 
25a06ca
 
36c1c11
40bf738
52fda00
bbc3d3d
 
40bf738
bbc3d3d
 
36c1c11
37fb541
40bf738
37fb541
edf6b35
40bf738
 
 
 
37fb541
44b349b
 
860576a
44b349b
37fb541
860576a
44b349b
 
 
 
860576a
44b349b
 
 
 
860576a
37fb541
faf6398
 
 
 
 
860576a
faf6398
860576a
f30c2aa
faf6398
 
617fb86
44b349b
faf6398
44b349b
 
 
40bf738
860576a
37fb541
36c1c11
52fda00
faf6398
860576a
36c1c11
 
617fb86
36c1c11
25a06ca
44b349b
40bf738
 
617fb86
 
 
 
 
 
40bf738
44b349b
 
 
40bf738
52fda00
25a06ca
36c1c11
 
 
 
40bf738
 
36c1c11
370bf2d
44b349b
 
37fb541
617fb86
44b349b
37fb541
 
36c1c11
8827f9c
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
import gradio as gr
import math

treasures = [
    {"name": "寶藏第1個", "lat": 24.985703, "lon": 121.288680},
    {"name": "寶藏第2個", "lat": 24.985900, "lon": 121.289000},
    {"name": "寶藏第3個", "lat": 24.956398, "lon": 121.297729},
]

def haversine(lat1, lon1, lat2, lon2):
    R = 6371000
    phi1, phi2 = math.radians(lat1), math.radians(lat2)
    d_phi = math.radians(lat2 - lat1)
    d_lambda = math.radians(lon2 - lon1)
    a = math.sin(d_phi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(d_lambda/2)**2
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
    return R * c

def check_nearest(lat, lon, found):
    if not lat or not lon:
        return "❌ 請先取得 GPS", "", "", found

    try:
        lat = float(lat)
        lon = float(lon)
    except:
        return "❌ 座標格式錯誤", "", "", found

    nearest = None
    nearest_idx = None
    min_distance = float("inf")

    for idx, treasure in enumerate(treasures):
        dist = haversine(lat, lon, treasure["lat"], treasure["lon"])
        if dist < min_distance:
            min_distance = dist
            nearest = treasure
            nearest_idx = idx

    dist = haversine(lat, lon, nearest["lat"], nearest["lon"])
    gmap = f"https://www.google.com/maps/dir/{lat},{lon}/{nearest['lat']},{nearest['lon']}"

    if dist <= 30 and nearest_idx not in found:
        found.append(nearest_idx)
        status = f"🎯 找到 {nearest['name']}!距離:{dist:.2f} 公尺 ✅"
        html = f"""
        <h3>{nearest['name']} 🎉 已找到!</h3>
        <img src="https://media.giphy.com/media/5GoVLqeAOo6PK/giphy.gif" style="width:100%; max-height:200px;">
        """
    elif nearest_idx in found:
        status = f"✅ {nearest['name']} 已找到!目前距離:{dist:.2f} 公尺"
        html = f'<a href="{gmap}" target="_blank">➡️ 再次導航至 {nearest["name"]}</a>'
    else:
        status = f"📍 距離 {nearest['name']}{dist:.2f} 公尺,請再靠近一些"
        html = f'<a href="{gmap}" target="_blank">➡️ 點我導航至 {nearest["name"]}</a>'

    if len(found) == len(treasures):
        html += """
        <h2 style="text-align:center;">🎉 所有寶藏已找到!</h2>
        <img src="https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExZGU4YzZhOTdjYjJmODlmZDEwZmExZDcyOTU4NGY5NGY4MzU3ZDM2YSZjdD1n/26n6WywJyh39n1pBu/giphy.gif" style="width:100%; max-height:300px;">
        """

    progress = f"✅ 已找到:{', '.join([treasures[i]['name'] for i in sorted(found)])}" if found else ""
    return status, html, progress, found

with gr.Blocks() as demo:
    gr.Markdown("# 🗺️ GPS 尋寶遊戲")
    gr.Markdown("📍 自動找最近寶藏,進入 30 公尺範圍內顯示動畫 🎉")

    gr.HTML("""
    <button id="gpsButton" style="padding:10px;font-size:16px;">📍 點我取得 GPS</button>
    <script>
    document.addEventListener("DOMContentLoaded", function () {
      document.getElementById("gpsButton").addEventListener("click", function () {
        navigator.geolocation.getCurrentPosition(
          function(pos) {
            const latbox = document.querySelectorAll("textarea")[0];
            const lonbox = document.querySelectorAll("textarea")[1];
            latbox.value = pos.coords.latitude;
            lonbox.value = pos.coords.longitude;
            latbox.dispatchEvent(new Event('input'));
            lonbox.dispatchEvent(new Event('input'));
          },
          function(err) {
            alert("⚠️ GPS 錯誤:" + err.message);
          }
        );
      });
    });
    </script>
    """)

    with gr.Row():
        lat = gr.Textbox(label="Latitude")
        lon = gr.Textbox(label="Longitude")

    status = gr.Markdown()
    link = gr.HTML()
    progress = gr.Markdown()
    found_state = gr.State([])

    btn = gr.Button("🔍 檢查距離 + 導航")
    btn.click(fn=check_nearest, inputs=[lat, lon, found_state],
              outputs=[status, link, progress, found_state])

demo.launch()