mirror of
https://github.com/GoodStartLabs/AI_Diplomacy.git
synced 2026-04-30 17:40:47 +00:00
184 lines
10 KiB
TypeScript
184 lines
10 KiB
TypeScript
// diplomacy/daide/responses.ts
|
|
|
|
import { Map as DiplomacyMap } from '../engine/map'; // Placeholder
|
|
import {
|
|
StringTs, PowerTs, ProvinceTs, TurnTs, UnitTs,
|
|
add_parentheses_ts, strip_parentheses_ts, parse_string_ts, AbstractClauseTs
|
|
} from './clauses';
|
|
import * as daideTokens from './tokens'; // Import all for token instances
|
|
import { Token } from './tokens';
|
|
import { daideBytesToString } from './utils';
|
|
// import { OrderSplitter } from '../utils/splitter'; // Placeholder
|
|
|
|
// Logger
|
|
const logger = {
|
|
debug: (message: string) => console.debug(message),
|
|
info: (message: string) => console.info(message),
|
|
warn: (message: string) => console.warn(message),
|
|
error: (message: string, error?: any) => console.error(message, error),
|
|
};
|
|
|
|
// Base DaideResponse class
|
|
// Note: This is for server-generated DAIDE responses. It's different from the client-side parsing of generic responses.
|
|
export abstract class DaideResponse {
|
|
protected _bytes: Uint8Array = new Uint8Array(0);
|
|
// If these responses need to link back to a request_id for client-side matching,
|
|
// it would typically be part of the wrapper message (e.g. DaideDiplomacyMessage content),
|
|
// not this low-level DAIDE command string.
|
|
// For now, keeping it simple as per Python structure which focuses on byte generation.
|
|
|
|
constructor() {}
|
|
|
|
toBytes(): Uint8Array {
|
|
return this._bytes;
|
|
}
|
|
|
|
toString(): string {
|
|
return daideBytesToString(this._bytes);
|
|
}
|
|
|
|
protected concatBytes(byteArrays: Uint8Array[]): Uint8Array {
|
|
let totalLength = 0;
|
|
for (const arr of byteArrays) {
|
|
totalLength += arr.length;
|
|
}
|
|
const result = new Uint8Array(totalLength);
|
|
let offset = 0;
|
|
for (const arr of byteArrays) {
|
|
result.set(arr, offset);
|
|
offset += arr.length;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Specific DAIDE Response Classes
|
|
|
|
export class MapNameResponseTs extends DaideResponse {
|
|
constructor(map_name: string) {
|
|
super();
|
|
const mapNameClause = parse_string_ts(StringTs, map_name, 'raise');
|
|
if (!mapNameClause) throw new Error("Failed to parse map name for MapNameResponse");
|
|
|
|
this._bytes = this.concatBytes([
|
|
daideTokens.MAP.toBytes(),
|
|
mapNameClause.toBytes() // StringTs toBytes already includes parentheses
|
|
]);
|
|
}
|
|
}
|
|
|
|
export class MapDefinitionResponseTs extends DaideResponse {
|
|
constructor(map_name: string, gameMapInstance?: DiplomacyMap) { // gameMapInstance for actual map data
|
|
super();
|
|
// const game_map = gameMapInstance || new DiplomacyMap(map_name); // Use instance or load
|
|
// For placeholder, we can't fully implement _build_..._clause methods without map data.
|
|
// This will be a simplified version.
|
|
|
|
const powersClause = this._build_powers_clause_stub();
|
|
const provincesClause = this._build_provinces_clause_stub();
|
|
const adjacenciesClause = this._build_adjacencies_clause_stub();
|
|
|
|
this._bytes = this.concatBytes([
|
|
daideTokens.MDF.toBytes(),
|
|
powersClause,
|
|
provincesClause,
|
|
adjacenciesClause
|
|
]);
|
|
}
|
|
|
|
private _build_powers_clause_stub(): Uint8Array {
|
|
// Simplified: ( (AUS) (ENG) ... )
|
|
const powerTokens = [daideTokens.AUS, daideTokens.ENG, daideTokens.FRA, daideTokens.GER, daideTokens.ITA, daideTokens.RUS, daideTokens.TUR];
|
|
const inner = this.concatBytes(powerTokens.map(pt => add_parentheses_ts(pt.toBytes())));
|
|
return add_parentheses_ts(inner);
|
|
}
|
|
private _build_provinces_clause_stub(): Uint8Array {
|
|
logger.warn("MapDefinitionResponseTs._build_provinces_clause_stub is a placeholder.");
|
|
return add_parentheses_ts(new Uint8Array(0)); // ( () () )
|
|
}
|
|
private _build_adjacencies_clause_stub(): Uint8Array {
|
|
logger.warn("MapDefinitionResponseTs._build_adjacencies_clause_stub is a placeholder.");
|
|
return add_parentheses_ts(new Uint8Array(0)); // ( () )
|
|
}
|
|
// Full implementation of _build_powers_clause, _build_provinces_clause, _build_adjacencies_clause
|
|
// would require a detailed DiplomacyMap placeholder and its data.
|
|
}
|
|
|
|
export class HelloResponseTs extends DaideResponse {
|
|
constructor(power_name: string, passcode: number, level: number, deadline: number, rules: string[]) {
|
|
super();
|
|
const powerClause = parse_string_ts(PowerTs, power_name, 'raise');
|
|
const passcodeToken = new Token({ from_int: passcode });
|
|
if (!powerClause) throw new Error("Failed to parse power name for HelloResponse");
|
|
|
|
let variantsBytes: Uint8Array[] = [];
|
|
variantsBytes.push(add_parentheses_ts(this.concatBytes([daideTokens.LVL.toBytes(), new Token({ from_int: level }).toBytes()])));
|
|
|
|
if (deadline > 0) {
|
|
const deadlineTokenBytes = new Token({ from_int: deadline }).toBytes();
|
|
variantsBytes.push(add_parentheses_ts(this.concatBytes([daideTokens.MTL.toBytes(), deadlineTokenBytes])));
|
|
variantsBytes.push(add_parentheses_ts(this.concatBytes([daideTokens.RTL.toBytes(), deadlineTokenBytes])));
|
|
variantsBytes.push(add_parentheses_ts(this.concatBytes([daideTokens.BTL.toBytes(), deadlineTokenBytes])));
|
|
}
|
|
if (rules.includes('NO_CHECK')) { // Example rule check
|
|
variantsBytes.push(add_parentheses_ts(daideTokens.AOA.toBytes()));
|
|
}
|
|
// Add other rules like PDA, NPR, NPB, PTL based on 'rules' array and DAIDE spec for LVL 10
|
|
if (rules.includes('PARTIAL_DRAWS_ALLOWED')) { // Made up rule name for example
|
|
variantsBytes.push(add_parentheses_ts(daideTokens.PDA.toBytes()));
|
|
}
|
|
// ... etc. for NPR, NPB, PTL if applicable based on level and rules
|
|
|
|
const allVariantsBytes = add_parentheses_ts(this.concatBytes(variantsBytes));
|
|
|
|
this._bytes = this.concatBytes([
|
|
daideTokens.HLO.toBytes(),
|
|
add_parentheses_ts(powerClause.toBytes()),
|
|
add_parentheses_ts(passcodeToken.toBytes()),
|
|
allVariantsBytes // This is already parenthesized in python: add_parentheses(bytes(variants))
|
|
// The `variants` string in python is already (LVL...)(MTL...). So one more pair of parens.
|
|
]);
|
|
}
|
|
}
|
|
|
|
// ... Other response classes will follow a similar pattern ...
|
|
// SupplyCenterResponse, CurrentPositionResponse, ThanksResponse, MissingOrdersResponse,
|
|
// OrderResultResponse, TimeToDeadlineResponse, AcceptResponse, RejectResponse,
|
|
// NotResponse, PowerInCivilDisorderResponse, PowerIsEliminatedResponse,
|
|
// TurnOffResponse, ParenthesisErrorResponse, SyntaxErrorResponse
|
|
|
|
// Stubs for remaining for brevity
|
|
export class SupplyCenterResponseTs extends DaideResponse { constructor(powers_centers: Record<string,string[]>, map_name: string){super(); logger.warn("SupplyCenterResponseTs not fully implemented")} }
|
|
export class CurrentPositionResponseTs extends DaideResponse { constructor(phase_name: string, powers_units: Record<string,string[]>, powers_retreats: Record<string,Record<string,string[]>>){super(); logger.warn("CurrentPositionResponseTs not fully implemented")} }
|
|
export class ThanksResponseTs extends DaideResponse { constructor(order_bytes: Uint8Array, results: number[]){super(); logger.warn("ThanksResponseTs not fully implemented")} }
|
|
export class MissingOrdersResponseTs extends DaideResponse { constructor(phase_name: string, power: any /*Power placeholder*/){super(); logger.warn("MissingOrdersResponseTs not fully implemented")} }
|
|
export class OrderResultResponseTs extends DaideResponse { constructor(phase_name: string, order_bytes: Uint8Array, results: number[]){super(); logger.warn("OrderResultResponseTs not fully implemented")} }
|
|
export class TimeToDeadlineResponseTs extends DaideResponse { constructor(seconds: number){super(); this._bytes = this.concatBytes([daideTokens.TME.toBytes(), add_parentheses_ts(new Token({from_int: seconds}).toBytes())]); } }
|
|
export class AcceptResponseTs extends DaideResponse { constructor(request_bytes: Uint8Array){super(); this._bytes = this.concatBytes([daideTokens.YES.toBytes(), add_parentheses_ts(request_bytes)]);} }
|
|
export class RejectResponseTs extends DaideResponse { constructor(request_bytes: Uint8Array){super(); this._bytes = this.concatBytes([daideTokens.REJ.toBytes(), add_parentheses_ts(request_bytes)]);} }
|
|
export class NotResponseTs extends DaideResponse { constructor(response_bytes: Uint8Array){super(); this._bytes = this.concatBytes([daideTokens.NOT.toBytes(), add_parentheses_ts(response_bytes)]);} }
|
|
export class PowerInCivilDisorderResponseTs extends DaideResponse { constructor(power_name: string){super(); const p = parse_string_ts(PowerTs, power_name, 'raise'); if(!p) throw new Error("Invalid power"); this._bytes = this.concatBytes([daideTokens.CCD.toBytes(), add_parentheses_ts(p.toBytes())]);} }
|
|
export class PowerIsEliminatedResponseTs extends DaideResponse { constructor(power_name: string){super(); const p = parse_string_ts(PowerTs, power_name, 'raise'); if(!p) throw new Error("Invalid power"); this._bytes = this.concatBytes([daideTokens.OUT.toBytes(), add_parentheses_ts(p.toBytes())]);} }
|
|
export class TurnOffResponseTs extends DaideResponse { constructor(){super(); this._bytes = daideTokens.OFF.toBytes();} }
|
|
export class ParenthesisErrorResponseTs extends DaideResponse { constructor(request_bytes: Uint8Array){super(); this._bytes = this.concatBytes([daideTokens.PRN.toBytes(), add_parentheses_ts(request_bytes)]);} }
|
|
export class SyntaxErrorResponseTs extends DaideResponse { constructor(request_bytes: Uint8Array, error_index: number){super(); const errTokenBytes = daideTokens.ERR.toBytes(); const msgWithErr = new Uint8Array(request_bytes.length + errTokenBytes.length); msgWithErr.set(request_bytes.slice(0, error_index)); msgWithErr.set(errTokenBytes, error_index); msgWithErr.set(request_bytes.slice(error_index), error_index + errTokenBytes.length); this._bytes = this.concatBytes([daideTokens.HUH.toBytes(), add_parentheses_ts(msgWithErr)]);} }
|
|
|
|
|
|
// Aliases
|
|
export const MAP = MapNameResponseTs;
|
|
export const MDF = MapDefinitionResponseTs;
|
|
export const HLO = HelloResponseTs;
|
|
export const SCO = SupplyCenterResponseTs;
|
|
export const NOW = CurrentPositionResponseTs;
|
|
export const THX = ThanksResponseTs;
|
|
export const MIS = MissingOrdersResponseTs;
|
|
export const ORD = OrderResultResponseTs;
|
|
export const TME = TimeToDeadlineResponseTs;
|
|
export const YES = AcceptResponseTs;
|
|
export const REJ = RejectResponseTs;
|
|
export const NOT = NotResponseTs;
|
|
export const CCD = PowerInCivilDisorderResponseTs;
|
|
export const OUT = PowerIsEliminatedResponseTs;
|
|
export const OFF = TurnOffResponseTs;
|
|
export const PRN = ParenthesisErrorResponseTs;
|
|
export const HUH = SyntaxErrorResponseTs;
|