|
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 java.util.Comparator;
import javafx.util.Sequences;
class ResourceItemWithTime {
var time: Number;
var resourceItem: ResourceItem;
}
class OptimTimeForWinResourceCount {
var timeoutExit: Boolean;
var time: Number;
var resourceSum: Number;
var resources: ResourceItem[];
var stopResource: ResourceItem;
}
class NearestDistForMeAndStranger {
var forMe: ResourceItem[];
var forStranger: ResourceItem[];
}
function sign(x:Number):Integer{
if ( x < 0 ) -1 else if ( 0 < x ) 1 else 0;
}
class ComparatorForMinDistanceFirst extends Comparator {
var spaceCraft : SpaceCraftItem;
var prg: Program;
public override function compare(obj1:Object, obj2: Object):Integer{
return sign (prg.distanceTime(spaceCraft, [(obj1 as ResourceItem)]) -
prg.distanceTime(spaceCraft, [(obj2 as ResourceItem)]));
}
public override function equals(obj:Object) : Boolean {
if (obj instanceof ComparatorForMinDistanceFirst) {
var sc = (obj as ComparatorForMinDistanceFirst).spaceCraft;
if (sc == spaceCraft) {
return true;
}
}
return false;
}
}
class ComparatorForMaxDistanceFirst extends Comparator {
var spaceCraft : SpaceCraftItem;
var prg: Program;
public override function compare(obj1:Object, obj2: Object):Integer{
return sign (prg.distanceTime(spaceCraft, [(obj2 as ResourceItem)]) -
prg.distanceTime(spaceCraft, [(obj1 as ResourceItem)]));
}
public override function equals(obj:Object) : Boolean {
if (obj instanceof ComparatorForMaxDistanceFirst) {
var sc = (obj as ComparatorForMaxDistanceFirst).spaceCraft;
if (sc == spaceCraft) {
return true;
}
}
return false;
}
}
Program{
name: "Spacecraft_6_9"
var startTrajectory: ResourceItem[];
var firstStep: Boolean = true;
var scanedMap: Boolean = false;
var firstDistScan = false;
var isFindFailed: Boolean = false;
var resourcesSum: Number;
var lastIndex = -1;
var activeIndex = -1;
var lastIndexCount = 0;
def normalExpensiveScan: Number = 15;
def percentIfNearestSpacecraft = 0.7;
def percentIfNormalSpacecraft = 0.5;
def percentIfFarSpacecraft = 0.3;
def dist: Number = 3.0;
def mistake = 500.0;
def attemptsCount = 2;
public override function setup():Void{
if (sizeof map.spacecrafts > 0 and sizeof map.resources > 0) {
resourcesSum = checkResourcesSum(map.resources);
var spacecrafts = sizeof map.spacecrafts + 1;
var startResourceForWint = resourcesSum / spacecrafts + 1;
startTrajectory = findTrajectory(map.resources, startResourceForWint);
}
}
function getPercentByDistance() : Number {
var dist = getMinDistForMe(map.spacecrafts);
if (dist < map.radius / 5) {
return percentIfNearestSpacecraft;
} else if (dist < map.radius / 3) {
return percentIfNormalSpacecraft;
} else {
return percentIfFarSpacecraft;
}
}
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 isResourceAtSamePosition(resource: ResourceItem, resources: ResourceItem[]) : Boolean {
for (item in resources) {
if (Point.distance(item, resource) <= dist) {
return true;
}
}
return false;
}
function getTimeNearestResourceAndTime(startPoints: Point[], resources: ResourceItem[]): ResourceItemWithTime {
var nearestResourceAndTime: ResourceItemWithTime;
var minTime = Number.MAX_VALUE;
for(resource in resources){
var distTime = distanceTime([startPoints, resource]);
if(distTime < minTime){
minTime = distTime;
nearestResourceAndTime = ResourceItemWithTime {time: distTime, resourceItem: resource};
}
}
return nearestResourceAndTime;
}
function getMinTimeResorcesAndCoast(resources: ResourceItem[], needResourceSum: Number): OptimTimeForWinResourceCount {
var copyOfResourceItems = resources;
var minTimeDistance: ResourceItem[];
var resultTime: Number = 0;
var resultSum: Number = 0;
var timeout: Boolean = false;
var isEnoughResources: Boolean = false;
var stopResource: ResourceItem = null;
while (sizeof copyOfResourceItems > 0) {
var nearestResourceAndTime = getTimeNearestResourceAndTime(minTimeDistance, copyOfResourceItems);
delete nearestResourceAndTime.resourceItem from copyOfResourceItems;
if (isResourceAtSamePosition(nearestResourceAndTime.resourceItem, minTimeDistance) == false) {
if (isEnoughResources == false) {
resultTime = nearestResourceAndTime.time;
}
if (nearestResourceAndTime.time > map.gameTime - time) {
if (isEnoughResources == false) {
timeout = true;
}
break;
}
insert nearestResourceAndTime.resourceItem into minTimeDistance;
}
if (isEnoughResources == false) {
resultSum += nearestResourceAndTime.resourceItem.value;
if (resultSum > needResourceSum) {
isEnoughResources = true;
stopResource = nearestResourceAndTime.resourceItem;
}
}
}
return OptimTimeForWinResourceCount{stopResource: stopResource,
timeoutExit: timeout,
time: resultTime,
resourceSum: resultSum,
resources: minTimeDistance};
}
function getNearestResourceAndCost(startPoints: Point[], resources: ResourceItem[]): ResourceItemWithTime {
var resourceAndTime: ResourceItemWithTime;
var maxCost: Number = Number.MIN_VALUE;
var minTime: Number = Number.MAX_VALUE;
for(resource in resources) {
if (resource.value >= maxCost) {
if (resource.value > maxCost) {
minTime = Number.MAX_VALUE;
}
maxCost = resource.value;
var distTime = distanceTime([startPoints, resource]);
if(distTime < minTime){
minTime = distTime;
resourceAndTime = ResourceItemWithTime{time: distTime, resourceItem: resource};
}
}
}
return resourceAndTime;
}
function getMostExpensiveResorcesAndCoast(resources: ResourceItem[], needResourceSum: Number): OptimTimeForWinResourceCount {
var copyOfResourceItems = resources;
var distance: ResourceItem[];
var resultTime: Number = 0;
var resultSum: Number = 0;
var timeout: Boolean = false;
var isEnoughResources: Boolean = false;
var stopResource: ResourceItem = null;
while (sizeof copyOfResourceItems > 0) {
var nearestResourceAndCost = getNearestResourceAndCost(distance, copyOfResourceItems);
delete nearestResourceAndCost.resourceItem from copyOfResourceItems;
if (isResourceAtSamePosition(nearestResourceAndCost.resourceItem, distance) == false) {
if (isEnoughResources == false) {
resultTime = nearestResourceAndCost.time;
}
if (nearestResourceAndCost.time > map.gameTime - time) {
if (isEnoughResources == false) {
timeout = true;
}
break;
}
insert nearestResourceAndCost.resourceItem into distance;
}
if (isEnoughResources == false) {
resultSum += nearestResourceAndCost.resourceItem.value;
if (resultSum > needResourceSum) {
isEnoughResources = true;
stopResource = nearestResourceAndCost.resourceItem;
}
}
}
return OptimTimeForWinResourceCount{stopResource: stopResource,
timeoutExit: timeout,
time: resultTime,
resourceSum: resultSum,
resources: distance};
}
function getDistanceNearestResource(startPoint: Point, resources: ResourceItem[]): ResourceItem {
var nearestResource: ResourceItem;
var minDist = Number.MAX_VALUE;
for(resource in resources){
var dist = Point.distance(startPoint, resource);
if(dist < minDist){
minDist = dist;
nearestResource = resource;
}
}
return nearestResource;
}
function getMinDistanceResorcesAndCoast(resources: ResourceItem[], needResourceSum: Number): OptimTimeForWinResourceCount {
var copyOfResourceItems = resources;
var minDistance: ResourceItem[];
var timeout: Boolean = false;
var isEnoughResources: Boolean = false;
var resultTime: Number = 0;
var resultSum: Number = 0;
var nearestResource: ResourceItem = null;
var stopResource: ResourceItem = null;
while (sizeof copyOfResourceItems > 0) {
if (nearestResource == null) {
nearestResource = getDistanceNearestResource(position, copyOfResourceItems);
} else {
nearestResource = getDistanceNearestResource(nearestResource, copyOfResourceItems);
}
delete nearestResource from copyOfResourceItems;
if (isResourceAtSamePosition(nearestResource, minDistance) == false) {
var tempTime = distanceTime([minDistance, nearestResource]);
if (isEnoughResources == false) {
resultTime = tempTime;
}
if (tempTime > map.gameTime - time) {
if (isEnoughResources == false) {
timeout = true;
}
break;
}
insert nearestResource into minDistance;
}
if (isEnoughResources == false) {
resultSum += nearestResource.value;
if (resultSum > needResourceSum) {
isEnoughResources = true;
stopResource = nearestResource;
}
}
}
return OptimTimeForWinResourceCount{stopResource: stopResource,
timeoutExit: timeout,
time: resultTime,
resourceSum: resultSum,
resources: minDistance};
}
function getSpaceCraftsMinDistForResource(resource: ResourceItem, spaceCrafts: SpaceCraftItem[]): Number {
var minDist = Number.MAX_VALUE;
for(space in spaceCrafts){
var dist = distanceTime(space, [resource]);
if(dist < minDist){
minDist = dist;
}
}
return minDist;
}
function getNearestResorcesDist(resources: ResourceItem[], spaceCrafts: SpaceCraftItem[]): NearestDistForMeAndStranger {
var resultResourcesForMe: ResourceItem[];
var resultResourcesForStranger: ResourceItem[];
var myDist: Number;
var strangerDist: Number;
for (resource in resources){
myDist = distanceTime([resource]);
strangerDist = getSpaceCraftsMinDistForResource(resource, spaceCrafts);
if (myDist <= strangerDist) {
insert resource into resultResourcesForMe;
} else {
insert resource into resultResourcesForStranger;
}
}
return NearestDistForMeAndStranger {forMe: resultResourcesForMe, forStranger: resultResourcesForStranger};
}
function findTrajectory(inputRes: ResourceItem[], resourcesNeedForWin: Number): ResourceItem[] {
if (sizeof inputRes < 2) return inputRes;
var lineTrajectoryOptimTime = linearization(getMinTimeResorcesAndCoast(inputRes, resourcesNeedForWin));
var lineTrajectoryOptimCost = linearization(getMostExpensiveResorcesAndCoast(inputRes, resourcesNeedForWin));
var lineTrajectoryOptimDist = linearization(getMinDistanceResorcesAndCoast(inputRes, resourcesNeedForWin));
var trajectory = null;
var trajectoryExpireTime = null;
var minTime = Number.MAX_VALUE;
var maxCost = Number.MIN_VALUE;
var optimTrajectorys: OptimTimeForWinResourceCount[] = [lineTrajectoryOptimTime, lineTrajectoryOptimCost, lineTrajectoryOptimDist];
for (item in optimTrajectorys) {
if (item.timeoutExit == false) {
if (item.time < minTime) {
trajectory = item;
minTime = item.time;
}
} else {
if (item.resourceSum > maxCost) {
trajectoryExpireTime = item;
maxCost = item.resourceSum;
}
}
}
if (trajectory != null) {
return trajectory.resources;
} else {
return trajectoryExpireTime.resources;
}
}
function isOnLine(p1:Point, p2:Point, p3:Point): Boolean {
var result = (p3.x - p1.x) * (p2.y - p1.y) - (p3.y - p1.y) * (p2.x - p1.x);
return Math.abs(result) < mistake;
}
function linearization(trajectory: OptimTimeForWinResourceCount): OptimTimeForWinResourceCount{
if (sizeof trajectory.resources < 2) return trajectory;
var time: Number = 0.0;
var linerizeResources: ResourceItem[];
var p1: Point = position;
var p2: Point = trajectory.resources[0];
var p3: Point;
var wasStopResource: Boolean = false;
for (item in trajectory.resources[1..]) {
if (trajectory.stopResource == item) {
wasStopResource = true;
}
p3 = item;
if (isOnLine(p1, p2, p3)) {
p2 = p3;
} else {
insert (p2 as ResourceItem) into linerizeResources;
p1 = p2;
p2 = p3;
if (wasStopResource == true) {
wasStopResource = false;
time = distanceTime(linerizeResources);
}
}
}
insert (p3 as ResourceItem) into linerizeResources;
if (time == 0.0) {
time = distanceTime(linerizeResources);
}
return OptimTimeForWinResourceCount{timeoutExit: trajectory.timeoutExit, time: time, resourceSum: trajectory.resourceSum, resources: linerizeResources};
}
function generateStrategy(resources: ResourceItem[], spaceCrafts: SpaceCraftItem[]): ResourceItem[] {
var resultTrajectory: ResourceItem[];
var nearestResoruces = getNearestResorcesDist(resources, spaceCrafts);
var myNearestResorcesSum = checkResourcesSum(nearestResoruces.forMe);
var resourcesNeedForWin = Math.round(resourcesSum / 2) - score + 1;
if (isFindFailed == false) {
return findTrajectory(nearestResoruces.forMe, resourcesNeedForWin);
}
if (myNearestResorcesSum >= resourcesNeedForWin) {
resultTrajectory = findTrajectory(nearestResoruces.forMe, resourcesNeedForWin);
} else if (sizeof resources < 3) {
var lastResources: ResourceItem[] = nearestResoruces.forMe;
if (sizeof nearestResoruces.forMe == 0) {
var sortedResourceForStranger = Sequences.sort(nearestResoruces.forStranger,
ComparatorForMinDistanceFirst{prg: this, spaceCraft: map.spacecrafts[0]}) as ResourceItem[];
if (sizeof sortedResourceForStranger > 1) {
lastResources = [sortedResourceForStranger[1]];
}
}
resultTrajectory = findTrajectory(lastResources, resourcesNeedForWin);
} else if (getMinDistForMe(map.spacecrafts) < map.radius / 5) {
var sortedResourceForStranger = Sequences.sort(nearestResoruces.forStranger,
ComparatorForMaxDistanceFirst{prg: this, spaceCraft: map.spacecrafts[0]}) as ResourceItem[];
var countOfNearestResourcesForStraner = sizeof nearestResoruces.forStranger;
var percentOfStartElementCount = getPercentByDistance();
var elementsCountFromStrangerNearestResources: Integer = Math.round(percentOfStartElementCount * countOfNearestResourcesForStraner);
var resorcesForTrajectoryResearch: ResourceItem[] = [nearestResoruces.forMe, sortedResourceForStranger[0..<elementsCountFromStrangerNearestResources]];
resultTrajectory = findTrajectory(resorcesForTrajectoryResearch, resourcesNeedForWin);
} else {
resultTrajectory = findTrajectory(nearestResoruces.forMe, resourcesNeedForWin);
}
if (sizeof resultTrajectory > 0) {
return resultTrajectory;
} else {
return findTrajectory(resources, Number.MAX_VALUE);
}
}
public override function nextStep():Action{
if (action == null) {
if (firstStep) {
firstStep = false;
return MoveAction{path: startTrajectory};
} else {
if (scanedMap) {
scanedMap = false;
var scanedResources = generateStrategy(map.resources, map.spacecrafts);
return MoveAction{path: scanedResources};
} else {
scanedMap = true;
return SpaceScanAction{};
}
}
} else {
if (action instanceof MoveAction) {
var act : MoveAction = action as MoveAction;
var activeResource = act.path[act.pathIndex] as ResourceItem;
var cont = map.containResource(activeResource);
if (not cont) {
if (act.pathIndex == lastIndex and lastIndexCount > attemptsCount) {
lastIndex = -1;
lastIndexCount = 0;
firstStep = false;
isFindFailed = true;
scanedMap = true;
return SpaceScanAction{};
} else {
lastIndex = act.pathIndex;
lastIndexCount++;
}
} else {
lastIndexCount = 0;
lastIndex = -1;
}
if (act.pathIndex > 0 and act.pathIndex != activeIndex and map.skip_time < normalExpensiveScan) {
if (firstDistScan == false and act.pathIndex < 2) {
firstDistScan = true;
} else if (Point.distance(act.path[act.pathIndex - 1], act.path[act.pathIndex]) > map.radius / 3) {
scanedMap = true;
return SpaceScanAction{};
}
}
activeIndex = act.pathIndex;
}
}
return null;
}
}
|
|