File size: 2,374 Bytes
4ee9ec9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# app.py
import uvicorn
from fastapi import FastAPI, Query, HTTPException
from fastapi.responses import PlainTextResponse
import numpy as np
import logging
import time

# Import our logic
from game_logic import parse_board_hex, is_game_over
from ai import find_best_move, get_dynamic_depth, SEARCH_DEPTH # Import base depth

logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)

app = FastAPI()

# Define the actual depth to use for this instance
# SET TO 6 IF YOU REALLY WANT, BUT BEWARE TIMEOUTS!
# Use dynamic depth instead:
# API_SEARCH_DEPTH = 6 

@app.get("/move", response_class=PlainTextResponse)
async def get_ai_move(board: str = Query(..., min_length=16, max_length=16, regex="^[0-9a-fA-F]{16}$")):
    """
    Receives a 16-char hex board string, returns the best move 'u','d','l','r' or 'g'.
    """
    log.info(f"Received board: {board}")
    start_time = time.time()
    try:
        board_array = parse_board_hex(board.upper())
        
        if is_game_over(board_array):
             log.info("Game Over detected.")
             return "g"

        # Use dynamic depth or fixed depth
        depth_to_use = get_dynamic_depth(board_array)
        # depth_to_use = API_SEARCH_DEPTH # Or use fixed
        
        log.info(f"Calculating move with depth {depth_to_use}...")
        move = find_best_move(board_array, depth=depth_to_use)
        
        duration = time.time() - start_time
        log.info(f"Replying with move: '{move}' in {duration:.4f}s")
        return move
        
    except ValueError as ve:
         log.error(f"Invalid board string: {board} - {ve}")
         raise HTTPException(status_code=400, detail="Invalid board string format.")
    except Exception as e:
        log.error(f"Internal error processing board {board}: {e}", exc_info=True)
        # Return a default or 'g' on error to not block the client too much
        # raise HTTPException(status_code=500, detail=str(e)) 
        return "g" # return game over on server error


# --- For HuggingFace Spaces ---
# HF Spaces looks for an app running on 0.0.0.0:7860
if __name__ == "__main__":
    log.info(f"Starting 2048 AI API with BASE_DEPTH={SEARCH_DEPTH}...")
    # For local testing: http://127.0.0.1:7860/move?board=0000000000100010
    # For HF Spaces: host must be 0.0.0.0, port must be 7860
    uvicorn.run(app, host="0.0.0.0", port=7860)