게시판오목 좌표 LoRA: 15×15와 19×19 격자를 정확히 읽히기예제 소스

예제 소스

오목 좌표 LoRA: 15×15와 19×19 격자를 정확히 읽히기 · 파일 59개

tcpvlmclient.h

#pragma once

#include <QAtomicInt>
#include <QByteArray>
#include <QImage>
#include <QObject>
#include <QString>

class QTcpSocket;

/** 오목 판 PNG + 169바이트 격자 상태를 TCP로 보내 VLM 서버의 좌표 응답을 받습니다.
 *
 * 새 모드(persistent): 한 번 연결한 소켓을 게임/앱 수명 동안 계속 재사용합니다.
 * 매 수마다 같은 소켓 위로 메시지를 보내고 응답을 받습니다. 서버도 한 클라이언트 연결을
 * 루프로 계속 응대합니다.
 */
namespace TcpVlmClient {

/**
 * QThread 위에 올려 두고 슬롯들을 QueuedConnection 으로 트리거합니다.
 * 결과는 시그널로 메인 스레드에 전달됩니다.
 *
 * 모든 소켓 접근은 워커 스레드에서만 일어나도록 invokeMethod 로 디스패치하세요.
 */
class Worker : public QObject {
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);
    ~Worker() override;

    bool isBusy() const;
    bool isConnected() const;

public slots:
    /// 연결 보장(없으면 connect). 결과는 \ref pingReady (success, error) 로 emit.
    void doPing(QString host, quint16 port, int timeoutMs);

    /// 한 수 요청. ensureConnected 후 같은 소켓 위로 OMK3 송수신. 결과는 \ref moveReady.
    /// boardSize: 13/15/19, aiSide: 1=Black, 2=White
    void requestMove(QImage boardImage, QByteArray boardPacked, int boardSize, int aiSide,
                     QString host, quint16 port, int timeoutMs);

    /// 학습용 기보 한 수를 *로깅 전용* 으로 서버에 전송 (추론 안 함).
    /// stone:1=Black,2=White / actor:0=human,1=local_ai,2=vlm / mode/status: enum 정수.
    void requestLog(int boardSize, int stone, int row, int col, int actor, int mode, int status,
                    int seq, QByteArray boardPacked, QString host, quint16 port, int timeoutMs);

    /// 진행 중 요청을 가능한 빨리 중단하고 소켓을 닫는다. 다음 요청 때 재연결.
    void cancel();

    /// 명시적으로 소켓을 닫는다. (모드 변경/앱 종료 시)
    void closeConnection();

signals:
    void moveReady(bool success, int row, int col, QString errorMessage);
    void pingReady(bool success, QString errorMessage);
    /// 연결 상태 변화 알림 (UI 표시용).
    void connectionStateChanged(bool connected, QString endpoint);

private:
    bool ensureConnected(const QString &host, quint16 port, int timeoutMs, QString *errorOut);
    bool readBytes(QByteArray *dst, qint64 nbytes, int deadlineMs);
    bool writeAll(const QByteArray &data, int timeoutMs);
    void closeSocketLocked(const QString &reason);
    void emitConnState();

    QTcpSocket *m_socket = nullptr;
    QString m_curHost;
    quint16 m_curPort = 0;

    QAtomicInt m_cancel{0};
    QAtomicInt m_busy{0};
};

} // namespace TcpVlmClient