bend_puzzle/shared-contracts.js
2026-08-01 16:06:14 +09:00

57 lines
2.4 KiB
JavaScript

'use strict';
(function attachSharedContracts(root,factory){
const api=factory();
if(typeof module==='object'&&module.exports)module.exports=api;
if(root)root.BendSharedContracts=api;
})(typeof globalThis!=='undefined'?globalThis:this,()=>{
const BOARD_ID_RE=/^B(?:0|[1-9][0-9]*)$/;
const CONTRACT_ID_RE=/^[A-Za-z0-9:_-]+$/;
const SPECIAL_MECHANIC_TYPES=Object.freeze(['warp','lock','crossing','internalGate']);
const SPECIAL_MECHANIC_SET=new Set(SPECIAL_MECHANIC_TYPES);
const DEFAULT_BUYER='\u65c5\u4eba';
function cleanContractId(value,maxLength=64){
const text=String(value||'').trim();
return text&&text.length<=maxLength&&CONTRACT_ID_RE.test(text)?text:'';
}
function cleanPlayerName(value,fallback=DEFAULT_BUYER){
const name=String(value||'').replace(/[\u0000-\u001f\u007f]/g,'').replace(/\s+/g,' ').trim().slice(0,24);
return name||fallback;
}
function normalizeSpecialMechanics(raw){
return[...new Set((Array.isArray(raw)?raw:[]).filter(type=>SPECIAL_MECHANIC_SET.has(type)))].sort();
}
function normalizePlayerPurchases(raw,{resolveItem=id=>({id}),maxPurchases=10000,maxPaidCost=Number.MAX_SAFE_INTEGER,defaultBuyer=DEFAULT_BUYER}={}){
const purchases=[],seenIds=new Set(),seenStoreItems=new Set();
for(const source of Array.isArray(raw)?raw:[]){
if(purchases.length>=maxPurchases)break;
const purchaseId=cleanContractId(source?.purchaseId,64),boardId=cleanContractId(source?.boardId,32),item=resolveItem(String(source?.itemId||'')),
storeKey=`${boardId}:${item?.id||''}`;
if(!purchaseId||!BOARD_ID_RE.test(boardId)||!item?.id||seenIds.has(purchaseId)||seenStoreItems.has(storeKey))continue;
const boughtAt=Number(source.boughtAt),paidCost=Number.isSafeInteger(source.paidCost)&&source.paidCost>=0?Math.min(source.paidCost,maxPaidCost):item.cost;
if(!Number.isSafeInteger(paidCost)||paidCost<0)continue;
seenIds.add(purchaseId);seenStoreItems.add(storeKey);
purchases.push({
purchaseId,
boardId,
itemId:item.id,
buyer:cleanPlayerName(source.buyer,defaultBuyer),
boughtAt:Number.isFinite(boughtAt)&&boughtAt>0?boughtAt:0,
paidCost
});
}
return purchases;
}
return Object.freeze({
BOARD_ID_RE,
SPECIAL_MECHANIC_TYPES,
cleanContractId,
cleanPlayerName,
normalizeSpecialMechanics,
normalizePlayerPurchases
});
});