|
package galaxyfx;
/**
* @author rantipin
*/
import galaxyfx.program.*;
import galaxyfx.program.action.*;
import galaxyfx.spacecraft.system.Point;
import galaxyfx.spacecraft.system.ResourceItem;
import galaxyfx.spacecraft.system.SpaceCraftItem;
import java.lang.Math;
import galaxyfx.spacecraft.system.CargoTerminalItem;
import java.util.HashMap;
class SpaceCraftAndResourceOnLine {
var spaceCraft: SpaceCraftItem;
var resourceOnLine: ResourceItem;
}
class OptimTimeForWinResourceCount {
var timeoutExit: Boolean;
var time: Number;
var coast: Number;
var action: CompoundAction;
}
class ResourceAndTime {
var resource: ResourceItem;
var timeForMe: Number;
var timeForStranger: Number;
}
class NearestDistForMeAndStranger {
var forMe: ResourceAndTime[];
var forStranger: ResourceAndTime[];
function getNearestForMe(): ResourceItem[] {
var res: ResourceItem[];
for(item in forMe) {
insert item.resource into res;
}
return res;
}
function getNearestForStranger(): ResourceItem[] {
var res: ResourceItem[];
for(item in forStranger) {
insert item.resource into res;
}
return res;
}
}
class NearestTerminal {
var pos: CargoTerminalItem;
var time: Number;
}
class SpaceCraftLastPosition {
var spaceCraft: SpaceCraftItem;
var isMoved: Boolean = false;
}
var terminals: CargoTerminalItem[];
var locCargoCapacity: Number;
var gameTime: Number;
var harvestTimeMap: HashMap;
var lastSpPositionMap: HashMap = new HashMap();
function copySpaceCraftItems(spaceCrafts: SpaceCraftItem[]): Void {
for(sp in spaceCrafts) {
var obj = lastSpPositionMap.get(sp.id);
if (obj instanceof SpaceCraftLastPosition) {
(obj as SpaceCraftLastPosition).spaceCraft = sp.copy();
} else {
lastSpPositionMap.put(sp.id, SpaceCraftLastPosition{spaceCraft: sp.copy()});
}
}
}
function isSpaceCraftNotMove(sp: SpaceCraftItem): Boolean {
var result: Boolean = false;
var obj = lastSpPositionMap.get(sp.id);
if (obj instanceof SpaceCraftLastPosition) {
var spLastPosition = (obj as SpaceCraftLastPosition);
var isMoved = Point.distance(sp, spLastPosition.spaceCraft) > 20;
if (not isMoved and not spLastPosition.isMoved){
result = true;
}
spLastPosition.isMoved = isMoved;
}
return result;
}
function findNearestTerminal(pos: Point): NearestTerminal {
var minDist: Number = Number.MAX_VALUE;
var nearestTerminal: CargoTerminalItem;
var dist: Number;
for (term in terminals) {
dist = Point.distance(pos, term);
if (dist < minDist) {
minDist = dist;
nearestTerminal = term;
}
}
return NearestTerminal{pos: nearestTerminal, time: minDist};
}
function calculateHarvestTime(resources: ResourceItem[]): Number {
var tempValue;
var harvestTime: Number = 0.0;
for(res in resources) {
tempValue = harvestTimeMap.get(res.value);
if (tempValue != null) {
harvestTime += tempValue as Number;
}
}
return harvestTime;
}
function createUnloadActions(point: Point): Action[] {
var nearestTerminal = findNearestTerminal(point).pos;
return [MoveAction {path: [nearestTerminal]}, UnloadAction {}];
}
function createUnloadActions(spaceCraft: Point, unloadCargo: Number): Action[] {
var nearestTerminal = findNearestTerminal(spaceCraft).pos;
return [MoveAction {path: [nearestTerminal]}, UnloadAction {limit:unloadCargo}];
}
function createHarvestActions(resource: ResourceItem, loadCargo: Number): Action[] {
return [MoveAction{path: [resource]}, HarvestAction{limit: loadCargo, target: resource}];
}
abstract class TrajectoryResearcher {
var prg: Program;
public abstract function findOptimResource(includedPoints: Point[], resources: ResourceItem[]): ResourceItem;
public abstract function findOptimTrafectory(resources: ResourceItem[], startPoint: ResourceItem): OptimTimeForWinResourceCount;
public function findTrafectorys(resources: ResourceItem[], startPoints: Integer): OptimTimeForWinResourceCount[] {
var points = startPoints;
var copyOfResources = resources;
var result: OptimTimeForWinResourceCount[];
var startItem: ResourceItem = null;
if (points > sizeof resources) {
points = sizeof resources;
}
if (points > 1) {
while (points-- > 0) {
startItem = findOptimResource([], copyOfResources);
delete startItem from copyOfResources;
insert findOptimTrafectory(resources[item | not item.equals(startItem)], startItem) into result;
}
} else {
insert findOptimTrafectory(resources, startItem) into result;
}
return result;
}
function trajectoryTime(res:ResourceItem[]): Number {
var lastPointBeforeTerminal: Point;
if (sizeof res > 0) {
lastPointBeforeTerminal = res[sizeof res - 1];
} else {
lastPointBeforeTerminal = prg.position;
}
var time = prg.distanceTime([res, findNearestTerminal(lastPointBeforeTerminal).pos]);
time += 20 + calculateHarvestTime(res);
return time;
}
public function generateCompoundAction(res:ResourceItem[]): CompoundAction {
var lastPointBeforeTerminal: Point;
var compoundAction = CompoundAction {};
if (sizeof res > 0) {
lastPointBeforeTerminal = res[sizeof res - 1];
for(item in res) {
insert createHarvestActions(item, item.value) into compoundAction.actions;
}
} else {
lastPointBeforeTerminal = prg.position;
}
insert createUnloadActions(lastPointBeforeTerminal) into compoundAction.actions;
return compoundAction;
}
}
abstract class TrajectoryForSpacecraft extends TrajectoryResearcher {
public override function findOptimTrafectory(resources: ResourceItem[], startPoint: ResourceItem): OptimTimeForWinResourceCount {
var copyOfResourceItems = resources;
var minTimeDistance: ResourceItem[];
var resultTime: Number;
var resultSum: Number = prg.cargo;
var timeout: Boolean = false;
if (startPoint != null) {
var distTime = trajectoryTime([startPoint]);
if (distTime > gameTime - prg.time) {
return OptimTimeForWinResourceCount{timeoutExit: true,
time: trajectoryTime([]),
coast: resultSum,
action: generateCompoundAction([])};
}
resultTime = distTime;
resultSum += startPoint.value;
insert startPoint into minTimeDistance;
}
while (sizeof copyOfResourceItems > 0) {
if (resultSum >= locCargoCapacity) {
break;
}
var resource = findOptimResource(minTimeDistance, copyOfResourceItems);
delete resource from copyOfResourceItems;
var distTime = trajectoryTime([minTimeDistance, resource]);
if (distTime > gameTime - prg.time) {
timeout = true;
break;
}
insert resource into minTimeDistance;
resultTime = distTime;
resultSum += resource.value;
}
return OptimTimeForWinResourceCount{timeoutExit: timeout,
time: resultTime,
coast: resultSum,
action: generateCompoundAction(minTimeDistance)};
}
}
class TimeForSpacecraft extends TrajectoryForSpacecraft {
public override function findOptimResource(includedPoints: Point[], resources: ResourceItem[]): ResourceItem {
var nearestResource: ResourceItem;
var minTime = Number.MAX_VALUE;
for(resource in resources){
var distTime = prg.distanceTime([includedPoints, resource]);
if(distTime < minTime){
minTime = distTime;
nearestResource = resource;
}
}
return nearestResource;
}
}
class FactorOptimForSpacecraft extends TrajectoryForSpacecraft {
var timeWeight: Number;
var costWeight: Number;
init {
costWeight = 1.0 - timeWeight;
}
public override function findOptimResource(includedPoints: Point[], resources: ResourceItem[]): ResourceItem {
var costSum: Number = 0;
var timeSum: Number = 0;
var distTime: Number = 0;
var minDistTime:Number = Number.MAX_VALUE;
var minTimeDistResource: ResourceItem;
var criterion;
var maxCriterion: Number = Number.MIN_VALUE;
var criterionTime: Number;
var foundResource: ResourceItem;
for(resource in resources) {
distTime = prg.distanceTime([includedPoints, resource]);
costSum += resource.value;
timeSum += 1 / distTime;
if (resource.value >= locCargoCapacity - prg.cargo and distTime < minDistTime) {
minDistTime = distTime;
minTimeDistResource = resource;
}
}
for(resource in resources) {
distTime = prg.distanceTime([includedPoints, resource]);
criterion = costWeight * resource.value / costSum + timeWeight / (distTime * timeSum);
if (criterion > maxCriterion) {
maxCriterion = criterion;
criterionTime = distTime;
foundResource = resource;
}
}
if (minDistTime < criterionTime) {
foundResource = minTimeDistResource;
}
return foundResource;
}
}
Program {
name: "Spacecraft_0_6"
autoHarvest: false;
options: TuningOptions {
cargo: 1,
speed: 3,
teamwork: 0,
radar: 0
}
var startCompoundAction: CompoundAction;
var spacecrafts: Integer;
var firstStep: Boolean = true;
var scanedMap: Boolean = false;
var resourcesSum: Number;
var lastScanTime: Number = 0;
public override function setup():Void {
if (sizeof map.spacecrafts > 0 and sizeof map.resources > 0) {
terminals = map.terminals;
locCargoCapacity = 120;
gameTime = map.gameTime;
harvestTimeMap = setupHarvestMap(map.resources);
resourcesSum = checkResourcesSum(map.resources);
startCompoundAction = generateStrategy(map.resources, map.spacecrafts);
}
}
function setupHarvestMap(resources: ResourceItem[]): HashMap {
var time;
var tempValue;
var mapValueTime: HashMap = new HashMap();
for(res in resources) {
tempValue = mapValueTime.get(res.value);
if (tempValue == null) {
time = timeToComplete(CompoundAction{actions: createHarvestActions(res, res.value)}, null)-
timeToComplete(CompoundAction{actions:MoveAction{path: [res]}}, null);
if (time <= 0) time = 5.0;
mapValueTime.put(res.value, time);
}
}
return mapValueTime;
}
function isStarFromOnePosition(spaceCrafts: SpaceCraftItem[]): Boolean {
for(spcr in spaceCrafts) {
if (not isSpaceCraftNotMove(spcr) and Point.distance(spcr, position) > 10) {
return false;
}
}
return true;
}
function getMinDistForMe(spaceCrafts: SpaceCraftItem[]) : Number {
var minDist = Number.MAX_VALUE;
for(spcr in spaceCrafts) {
var dist = Point.distance(spcr, position);
if(dist < minDist) {
minDist = dist;
}
}
return minDist;
}
function checkResourcesSum (resources: ResourceItem[]) : Number {
var sum: Number = 0.0;
for (resource in resources) {
sum += resource.value;
}
return sum;
}
function getSpaceCraftsMinDistForResource(resource: ResourceItem, spaceCraftAndResourceOnLine: SpaceCraftAndResourceOnLine[]): Number {
var minDist: Number = Number.MAX_VALUE;
var dist: Number;
for(space in spaceCraftAndResourceOnLine){
if (space.resourceOnLine == null) {
dist = distanceTime(space.spaceCraft, [resource]);
} else {
dist = distanceTime(space.spaceCraft, [space.resourceOnLine, resource]);
}
if(dist < minDist){
minDist = dist;
}
}
return minDist;
}
def fault: Number = 1e-6;
function getResourceOnLine(resources: ResourceItem[], spaceCraft: SpaceCraftItem): ResourceItem {
var tan = Math.tan(spaceCraft.direction);
var localDirection = 0.0;
var x = spaceCraft.x;
var y = spaceCraft.y;
var y_sign = 0.0;
var x_sign = 0.0;
var minDist: Number = Number.MAX_VALUE;
var foundResource: ResourceItem = null;
var checkResourceDist = function (item: ResourceItem):Void{
var dist = Point.distance(spaceCraft, item);
if (dist < minDist) {
minDist = dist;
foundResource = item;
}
};
if (spaceCraft.direction < -Math.PI) {
localDirection = 2*Math.PI + spaceCraft.direction;
} else if(spaceCraft.direction > Math.PI) {
localDirection = -2*Math.PI + spaceCraft.direction;
} else {
localDirection = spaceCraft.direction;
}
for (item in map.resources) {
x_sign = item.x - x;
y_sign = item.y - y;
if (Math.abs(x_sign) < fault and Math.abs(Math.abs(localDirection) - Math.PI / 2) < fault) {
if ((y_sign >= 0 and localDirection > 0) or (y_sign <= 0 and localDirection < 0)) {
checkResourceDist(item);
}
} else if (Math.abs(y_sign) < fault) {
if ((Math.abs(Math.abs(localDirection) - Math.PI) < fault and x_sign <= 0) or
(Math.abs(localDirection) < fault and x_sign >= 0)) {
checkResourceDist(item);
}
} else {
var value = (x_sign) * tan - (y_sign);
if (Math.abs(value) < 0.1 and
((y_sign >= 0 and localDirection > 0) or (y_sign <= 0 and localDirection < 0))) {
checkResourceDist(item);
}
}
}
return foundResource;
}
function getSpaceCraftsWithResourceOnLine(resources: ResourceItem[], spaceCrafts: SpaceCraftItem[]): SpaceCraftAndResourceOnLine[]{
var result: SpaceCraftAndResourceOnLine[];
var resourceOnLine: ResourceItem;
for(sp in spaceCrafts) {
resourceOnLine = getResourceOnLine(resources, sp);
insert SpaceCraftAndResourceOnLine{spaceCraft: sp, resourceOnLine: resourceOnLine} into result;
}
return result;
}
function getNearestResorcesDist(resources: ResourceItem[], spaceCrafts: SpaceCraftItem[]): NearestDistForMeAndStranger {
var resultResourcesForMe: ResourceAndTime[];
var resultResourcesForStranger: ResourceAndTime[];
var myDist: Number;
var strangerDist: Number;
var sizeSecStranger:Integer;
var spaceCraftAndResourceOnLine = getSpaceCraftsWithResourceOnLine(resources, spaceCrafts[sp|not isSpaceCraftNotMove(sp)]);
for (resource in resources) {
myDist = distanceTime([resource]);
strangerDist = getSpaceCraftsMinDistForResource(resource, spaceCraftAndResourceOnLine);
if (myDist <= strangerDist) {
insert ResourceAndTime{resource: resource, timeForMe: myDist, timeForStranger: strangerDist} into resultResourcesForMe;
} else {
sizeSecStranger = sizeof resultResourcesForStranger;
for(resForStranger in resultResourcesForStranger) {
if (resForStranger.timeForStranger > strangerDist) {
insert ResourceAndTime{resource: resource, timeForMe: myDist, timeForStranger: strangerDist} before resultResourcesForStranger[indexof resForStranger];
break;
}
}
if (sizeSecStranger == sizeof resultResourcesForStranger) {
insert ResourceAndTime{resource: resource, timeForMe: myDist, timeForStranger: strangerDist} into resultResourcesForStranger;
}
}
}
return NearestDistForMeAndStranger {forMe: resultResourcesForMe, forStranger: resultResourcesForStranger};
}
function findTrajectory(inputRes: ResourceItem[]): OptimTimeForWinResourceCount {
var trajectoryOptimTime = TimeForSpacecraft{prg: this}.findTrafectorys(inputRes, 3);
var trajectoryFactorOptim = FactorOptimForSpacecraft{prg: this, timeWeight: 0.7}.findTrafectorys(inputRes, 3);
var trajectoryMaxCoast: OptimTimeForWinResourceCount[];
if (isStarFromOnePosition(map.spacecrafts)) {
trajectoryMaxCoast = [
FactorOptimForSpacecraft{prg: this, timeWeight: 0.2}.findTrafectorys(inputRes, 2),
FactorOptimForSpacecraft{prg: this, timeWeight: 0.4}.findTrafectorys(inputRes, 2)];
}
var trajectory = null;
var trajectoryExpireTime = null;
var minTime = Number.MAX_VALUE;
var maxCost = Number.MIN_VALUE;
var optimTrajectorys: OptimTimeForWinResourceCount[] = [trajectoryOptimTime,
trajectoryFactorOptim,
trajectoryMaxCoast];
for (item in optimTrajectorys) {
if (not item.timeoutExit) {
if (item.time <= minTime) {
trajectory = item;
minTime = item.time;
}
} else {
if (item.coast >= maxCost) {
trajectoryExpireTime = item;
maxCost = item.coast;
}
}
}
if (trajectory != null) {
return trajectory;
} else {
return trajectoryExpireTime;
}
}
function needTermination(start: Point, stop:Point): CargoTerminalItem {
var dist = Point.distance(start, stop);
var a = stop.y - start.y;
var b = start.x - stop.x;
var c = -(start.y * b + start.x * a);
for (term in map.terminals) {
var distForStartPoint = Point.distance(start, term);
var distForStopPoint = Point.distance(term, stop);
var d = Math.abs(a * term.x + b * term.y + c) / Math.sqrt(a * a + b * b);
if (distForStartPoint <= dist and distForStopPoint <= dist and d <= dist / 4 and
(score + cargo) < resourcesSum * 0.3 and cargo > locCargoCapacity * 0.85) {
return term;
}
}
return null;
}
function generateStrategy(resources: ResourceItem[], spaceCrafts: SpaceCraftItem[]): CompoundAction {
stepAfterScan = 0;
var resultTrajectory: CompoundAction;
var nearestResoruces = getNearestResorcesDist(resources, spaceCrafts);
var myNearestResorcesSum = checkResourcesSum(nearestResoruces.getNearestForMe());
var resourcesNeedForWin = (resourcesSum / 2 + 1) - (score + cargo);
var resourcesNeedForFullCargo = locCargoCapacity - cargo;
if (sizeof resources < 3) {
var lastResources: ResourceItem[] = nearestResoruces.getNearestForMe();
if (sizeof nearestResoruces.forMe == 0) {
if (sizeof nearestResoruces.forStranger > 1) {
lastResources = [nearestResoruces.getNearestForStranger()[1]];
} else {
lastResources = [nearestResoruces.getNearestForStranger()[0]];
}
}
resultTrajectory = findTrajectory(lastResources).action;
} else if (myNearestResorcesSum > resourcesNeedForWin) {
resultTrajectory = findTrajectory(nearestResoruces.getNearestForMe()).action;
} else {
var resourceForStranger = nearestResoruces.getNearestForStranger();
var countResForStranger = sizeof resourceForStranger;
if (countResForStranger > 3) {
resourceForStranger = resourceForStranger[2..];
} else if (countResForStranger > 2) {
resourceForStranger = resourceForStranger[1..];
}
if (myNearestResorcesSum * 0.8 > checkResourcesSum(resourceForStranger)) {
resultTrajectory = findTrajectory([nearestResoruces.getNearestForMe()]).action;
} else {
resultTrajectory = findTrajectory([nearestResoruces.getNearestForMe(), resourceForStranger]).action;
}
}
copySpaceCraftItems(spaceCrafts);
return resultTrajectory;
}
function isStrangerSpaceCraftOnResourceItem(spaceCrafts: SpaceCraftItem[], resource: ResourceItem ): Boolean {
for (sp in spaceCrafts) {
if (sp.x == resource.x and sp.y == resource.y) {
return true;
}
}
return false;
}
function isShortStep(compoundAction: CompoundAction): Boolean {
if (compoundAction.actions[0] instanceof MoveAction) {
var moveAction = compoundAction.actions[0] as MoveAction;
if (Point.distance(position, moveAction.path[0]) < map.radius / 4) {
return true;
}
}
return false;
}
function isTerminalStep(compoundAction: CompoundAction) : Boolean {
if (sizeof compoundAction.actions > 2) {
return false;
}
return true;
}
function generateSpaceScanAction (): Action {
var timeAfterScan = time - map.timestamp;
if (timeAfterScan <= 30) {
return generateStrategy(map.resources, map.spacecrafts);
} else if (timeAfterScan <= 50) {
var compoundAction = generateStrategy(map.resources, map.spacecrafts);
if (isShortStep(compoundAction)) {
return compoundAction;
}
}
return SpaceScanAction{};
}
var lastActiveResource: ResourceItem = null;
var isCargoTerminal: Boolean = false;
var stepAfterScan: Integer = 0;
public override function nextStep():Action{
if (action == null) {
locCargoCapacity = cargoCapacity;
if (firstStep) {
firstStep = false;
return startCompoundAction;
} else {
if (scanedMap) {
scanedMap = false;
return generateStrategy(map.resources, map.spacecrafts);
} else {
return generateSpaceScanAction();
}
}
} else {
if (action instanceof CompoundAction) {
var act : CompoundAction = action as CompoundAction;
var curAction = act.actions[act.currentIndex];
if (curAction instanceof MoveAction) {
var moveAction: MoveAction = curAction as MoveAction;
var currentPosition = moveAction.path[moveAction.pathIndex];
if (currentPosition instanceof ResourceItem) {
isCargoTerminal = false;
var activeResource = currentPosition as ResourceItem;
if (not map.containResource(activeResource)) {
if (sizeof radar.spacecrafts > 0) {
var compoundAction = generateStrategy(map.resources, radar.spacecrafts);
if (isShortStep(compoundAction) and not isTerminalStep(compoundAction)) {
return compoundAction;
}
}
return SpaceScanAction{};
}
if (not activeResource.equals(lastActiveResource)) {
if (lastActiveResource != null) {
var terminal = needTermination(lastActiveResource, activeResource);
if (terminal != null) {
isCargoTerminal = true;
return CompoundAction{actions: [createUnloadActions(terminal)]};
}
}
var pointsDist = Point.distance(position, activeResource);
if ((stepAfterScan > 1 and pointsDist > map.radius * 0.6 and (sizeof radar.spacecrafts) == 0) or
(stepAfterScan > 0 and pointsDist > map.radius * 1.0)) {
if (sizeof radar.resources > 0) {
var compoundAction = generateStrategy(radar.resources, radar.spacecrafts);
if (not isTerminalStep(compoundAction)) {
return compoundAction;
}
return generateSpaceScanAction();
} else {
return generateSpaceScanAction();
}
}
stepAfterScan++;
}
lastActiveResource = activeResource;
} else if (currentPosition instanceof CargoTerminalItem and
sizeof map.resources > 0 and not isCargoTerminal) {
var resSum = checkResourcesSum(map.resources);
if((locCargoCapacity - cargo >= resSum * 0.2) or
(cargo < locCargoCapacity * 0.85) or
(findNearestTerminal(position).time > map.radius * 0.3 and cargo < locCargoCapacity * 0.9)) {
isCargoTerminal = true;
resSum = checkResourcesSum(radar.resources);
if (resSum > 0) {
var compoundAction = generateStrategy(radar.resources, radar.spacecrafts);
if (not isTerminalStep(compoundAction)) {
return compoundAction;
}
return generateSpaceScanAction();
} else {
return generateSpaceScanAction();
}
}
}
} else if (curAction instanceof HarvestAction) {
var harvestAction: HarvestAction = curAction as HarvestAction;
var limit: Number;
if (lastActiveResource.value <= 10) {
limit = lastActiveResource.value * 0.75;
} else {
limit = lastActiveResource.value / 2;
}
if (harvestAction.limit <= limit and isStrangerSpaceCraftOnResourceItem(radar.spacecrafts, lastActiveResource) and sizeof map.resources > 2) {
var radarResources = radar.resources[item | not item.equals(lastActiveResource)];
var resSum = checkResourcesSum(radarResources);
if (resSum >= (locCargoCapacity - cargo) / 2) {
var compoundAction = generateStrategy(radar.resources, radar.spacecrafts);
if (not isTerminalStep(compoundAction)) {
return compoundAction;
}
return generateSpaceScanAction();
}
}
} else if (curAction == null) {
return generateSpaceScanAction();
}
} else if (action instanceof SpaceScanAction) {
scanedMap = true;
}
}
return null;
}
}
|
|