Created
August 3, 2016 08:30
-
-
Save maximov-ru/9225f2a448df7e8c27f187a1ffb9e737 to your computer and use it in GitHub Desktop.
coding game
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* It's the survival of the biggest! | |
* Propel your chips across a frictionless table top to avoid getting eaten by bigger foes. | |
* Aim for smaller oil droplets for an easy size boost. | |
* Tip: merging your chips will give you a sizeable advantage. | |
**/ | |
fscanf(STDIN, "%d", | |
$playerId // your id (0 to 4) | |
); | |
class Ship | |
{ | |
public static $otherShipsMap; | |
public static $ownShipsMap; | |
public static $ownShips = []; | |
public static $playerId = 1; | |
const XSize = 799; | |
const YSize = 514; | |
const XCenter = 399; | |
const YCenter = 257; | |
public $id; | |
public $player; | |
public $radius; | |
public $x; | |
public $y; | |
public $vx; | |
public $vy; | |
public $isLive = true; | |
//public $ax; | |
//public $ay; | |
public $lastTargetId; | |
public $lastAction; | |
public static function resetLive() | |
{ | |
if(self::$ownShipsMap) { | |
foreach (self::$ownShipsMap as $ship) { | |
$ship->isLive = false; | |
} | |
} | |
if(self::$otherShipsMap) { | |
foreach (self::$otherShipsMap as $ship) { | |
$ship->isLive = false; | |
} | |
} | |
self::$ownShips = []; | |
} | |
public static function updateObject($id,$player,$radius,$x,$y,$vx,$vy) | |
{ | |
if($player == self::$playerId){ | |
if(!isset(self::$ownShipsMap[$id])){ | |
self::$ownShipsMap[$id] = new Ship(); | |
self::$ownShipsMap[$id]->id = $id; | |
self::$ownShipsMap[$id]->player = $player; | |
} | |
self::$ownShips[] = $id; | |
self::$ownShipsMap[$id]->updateData($radius,$x,$y,$vx,$vy); | |
}else{ | |
if(!isset(self::$otherShipsMap[$id])) { | |
self::$otherShipsMap[$id] = new Ship(); | |
self::$otherShipsMap[$id]->id = $id; | |
self::$otherShipsMap[$id]->player = $player; | |
} | |
self::$otherShipsMap[$id]->updateData($radius,$x,$y,$vx,$vy); | |
} | |
error_log(var_export("upd:".implode(' ',[$id,$player,$radius,$x,$y,$vx,$vy]), true)); | |
} | |
public function updateData($radius,$x,$y,$vx,$vy){ | |
//$this->id = $id; | |
//$this->player = $player; | |
$this->radius = $radius; | |
$this->x = $x; | |
$this->y = $y; | |
$this->vx = $vx; | |
$this->vy = $vy; | |
$this->isLive = true; | |
} | |
public static function getDist($x1,$y1,$x2,$y2) | |
{ | |
$dx = $x1>$x2 ? ($x1 - $x2) : ($x2 - $x1); | |
$dy = $y1>$y2 ? ($y1 - $y2) : ($y2 - $y1); | |
return sqrt($dx*$dx + $dy*$dy); | |
} | |
public function getNewRadiusAndSpeed() | |
{ | |
//1520.53 | |
$mass = pi()*$this->radius*$this->radius; | |
//101.37 p = 101.37*200 = 20274 | |
$sub = $mass/15; | |
//newMass = 1419.16 v = 20274/1419.16 = 14.29 | |
$newMass = $mass-$sub; | |
$speed = ($sub*200)/$newMass; | |
$radius = sqrt($newMass/pi()); | |
return [$radius,$speed]; | |
} | |
public static function changeCoord(&$x,&$y,&$vx,&$vy,$radius) | |
{ | |
$x +=$vx; | |
if($x<0) { | |
$x = abs($x); | |
$vx *= -1; | |
} | |
if($x > self::XSize){ | |
$x = self::XSize - ($x - self::XSize); | |
$vx *= -1; | |
} | |
$y +=$vy; | |
if($y<0) { | |
$y = abs($y); | |
$vy *= -1; | |
} | |
if($y > self::YSize){ | |
$y = self::YSize - ($y - self::YSize); | |
$vy *= -1; | |
} | |
} | |
public static function getCoord($x,$y,$vx,$vy,$radius) | |
{ | |
$x +=$vx; | |
if(($x-$radius)<0) { | |
$x = abs($x); | |
$vx *= -1; | |
} | |
if(($x+$radius) > self::XSize){ | |
$x = self::XSize - ($x - self::XSize); | |
$vx *= -1; | |
} | |
$y +=$vy; | |
if(($y-$radius)<0) { | |
$y = abs($y); | |
$vy *= -1; | |
} | |
if(($y+$radius) > self::YSize){ | |
$y = self::YSize - ($y - self::YSize); | |
$vy *= -1; | |
} | |
return [$x,$y]; | |
} | |
public function getSpeeds($dt,Ship $obj) | |
{ | |
list($newRad,$spd) = $this->getNewRadiusAndSpeed(); | |
$coords = self::getCoord($obj->x,$obj->y,$obj->vx*$dt,$obj->vy*$dt,$obj->radius); | |
$recosh = 0; | |
if($this->x < self::XCenter && ($this->x < $dt*$spd)){ | |
$recosh = $dt*$spd-$newRad; | |
}elseif($this->x > self::XCenter && ((self::XSize - $this->x) < $dt*$spd)){ | |
$recosh = $dt*$spd-$newRad; | |
} | |
} | |
public function getPossibleCross($dt,Ship $obj,$step = 1) | |
{ | |
/** | |
* x = (Vx1 + dVx)*t+a | |
* y = (Vy1 + dVy)*t+b | |
* | |
* x = Vx2*t+a2 | |
* y = Vy2*t+b2 | |
* | |
* dV^2 = dVx^2+dVy^2 | |
* | |
* dVx = √(dV^2 - dVy^2) | |
* | |
* t = (x-a2)/Vx2 | |
* | |
* x = (Vx1 + (sqrt(dV*dV - dVy*dVy)))*((x-a2)/Vx2)+a | |
* | |
* | |
* dVx = -Vx1-a/t-recosh/t+x/t | |
*/ | |
$x1 = $this->x; | |
$y1 = $this->y; | |
$vx1 = $this->vx*$step; | |
$vy1 = $this->vy*$step; | |
$dvx1 = 0; | |
$dvy1 = 0; | |
$t = 0; | |
$x2 = $obj->x; | |
$y2 = $obj->y; | |
$vx2 = $obj->vx*$step; | |
$vy2 = $obj->vy*$step; | |
$dist = self::getDist($x1,$y1,$x2,$y2); | |
$minRange = $dist; | |
$xn = $x1; | |
$yn = $y1; | |
$vxn = $vx1; | |
$vyn = $vy1; | |
$x3 = $xn; | |
$vx3 = $vxn+10*$step; | |
$y3 = $yn; | |
$vy3 = $vyn; | |
self::changeCoord($x3,$y3,$vx3,$vy3); | |
$dist3 = self::getDist($x3,$y3,$x2,$y2); | |
if($dist3<$dist){ | |
$dvx1 = 1; | |
}elseif($dist3>$dist){ | |
$dvx1 = -1; | |
}else{ | |
$dvx1 = 0; | |
} | |
$x3 = $xn; | |
$vx3 = $vxn; | |
$y3 = $yn; | |
$vy3 = $vyn+10*$step; | |
self::changeCoord($x3,$y3,$vx3,$vy3); | |
$dist3 = self::getDist($x3,$y3,$x2,$y2); | |
if($dist3<$dist){ | |
$dvy1 = 1; | |
}elseif($dist3>$dist){ | |
$dvy1 = -1; | |
}else{ | |
$dvy1 = 0; | |
} | |
$minT = $t; | |
for($t=1;$t<=$dt;$t++){ | |
$xn = $x1; | |
$yn = $y1; | |
$vxn = $vx1; | |
$vyn = $vy1; | |
self::changeCoord($x1,$y1,$vx1,$vy1); | |
self::changeCoord($x2,$y2,$vx2,$vy2); | |
$dist = self::getDist($x1,$y1,$x2,$y2); | |
if($dist<$minRange) { | |
$minRange = $dist; | |
$x3 = $xn; | |
$vx3 = $vxn+10*$step; | |
$y3 = $yn; | |
$vy3 = $vyn; | |
self::changeCoord($x3,$y3,$vx3,$vy3); | |
$dist3 = self::getDist($x3,$y3,$x2,$y2); | |
if($dist3<$dist){ | |
$dvx1 = 1; | |
}elseif($dist3>$dist){ | |
$dvx1 = -1; | |
}else{ | |
$dvx1 = 0; | |
} | |
$x3 = $xn; | |
$vx3 = $vxn; | |
$y3 = $yn; | |
$vy3 = $vyn+10*$step; | |
self::changeCoord($x3,$y3,$vx3,$vy3); | |
$dist3 = self::getDist($x3,$y3,$x2,$y2); | |
if($dist3<$dist){ | |
$dvy1 = 1; | |
}elseif($dist3>$dist){ | |
$dvy1 = -1; | |
}else{ | |
$dvy1 = 0; | |
} | |
$minT = $t; | |
} | |
} | |
return [$minRange,$minT,$dvx1,$dvy1]; | |
} | |
public function getAction() | |
{ | |
$act = 'WAIT'; | |
$dvx = 0; | |
$dvy = 0; | |
$canEat = false; | |
$isDrapaem = false; | |
$tPrior = 10; | |
$tPriorEat = 5; | |
$objId = null; | |
/*if($this->lastTargetId && self::$otherShipsMap[$this->lastTargetId]->isLive){ | |
$ship = self::$otherShipsMap[$this->lastTargetId]; | |
$crossInfo = $this->getPossibleCross(4, $ship); | |
error_log(var_export("target id {$this->id}({$this->radius}) njamnjam to {$ship->id}({$ship->radius})", true)); | |
if($this->radius/$ship->radius>1.1) { | |
$dvx = ($crossInfo[2]); | |
$dvy = ($crossInfo[3]); | |
error_log(var_export("target id {$this->id}({$this->radius}) njamnjam to {$ship->id}({$ship->radius}) player: {$ship->player}" . $dvx . ' ' . $dvy, true)); | |
if ($dvx || $dvy) { | |
$px = $this->x + $dvx; | |
if ($px < 0) { | |
$px = 0; | |
} | |
if ($px > self::XSize) { | |
$px = self::XSize; | |
} | |
$py = $this->y + $dvy; | |
if ($py < 0) { | |
$py = 0; | |
} | |
if ($py > self::YSize) { | |
$py = self::YSize; | |
} | |
$act = $px . ' ' . $py; | |
} | |
}else{ | |
$act = 'WAIT'; | |
} | |
return $act; | |
}*/ | |
if (self::$otherShipsMap) { | |
$minDistance = 700 * 3; | |
$maxWeight = 0; | |
foreach (self::$otherShipsMap as $id => $ship) { | |
if ($ship->isLive) { | |
$koef = $this->radius/$ship->radius; | |
if (self::getDist($this->x, $this->y, $ship->x, $ship->y) < (200 + $this->vx * $this->vx + $this->vy * $this->vy)) { | |
if (($ship->radius + 1) > $this->radius) { | |
//drapaem | |
$crossInfo = $this->getPossibleCross(10, $ship, 0.5); | |
if ($crossInfo[0] <= ($ship->radius + 1 + $this->radius)) { | |
if ($crossInfo[1] < $tPrior) { | |
$k = 6 - $crossInfo[1]; | |
$dvx += (-$crossInfo[2] * $k); | |
$dvy += (-$crossInfo[3] * $k); | |
if(!$dvx && !$dvy){ | |
$dvx = $this->x - $ship->x; | |
$dvy = $this->y - $ship->y; | |
} | |
$objId = $id; | |
$tPrior = $crossInfo[1]; | |
$isDrapaem = true; | |
error_log(var_export("id {$this->id}({$this->radius}) drapaem X2 from {$ship->id}({$ship->radius}) " . $dvx . ' ' . $dvy . " cross dist:{$crossInfo[0]} t:{$crossInfo[1]}", true)); | |
} | |
} | |
error_log(var_export("id {$this->id}({$this->radius}) drapaem from {$ship->id}({$ship->radius}) " . $dvx . ' ' . $dvy . " cross dist:{$crossInfo[0]} t:{$crossInfo[1]}", true)); | |
} elseif (!$isDrapaem && ($koef>1.1) && ($koef<4)) { | |
//dogonaem | |
$canEat = true; | |
$crossInfo = $this->getPossibleCross(4, $ship); | |
$weight = 0; | |
if($crossInfo[1] == 1 && ($crossInfo[0]< ($this->radius+$ship->radius))){ | |
$weight = 30000; | |
} | |
if($crossInfo[0] == 0){ | |
$obr = 1; | |
}else{ | |
$obr =$crossInfo[0]; | |
} | |
$timekMap = [10000,2000,1000,500]; | |
$weight += 10000/$obr + $timekMap[$crossInfo[1]] + 1000/$koef; | |
//$crossInfo[0] = $crossInfo[0] * $crossInfo[1]; | |
//if ($ship->player == -1) | |
// $crossInfo[0] = $crossInfo[0] / 2; | |
if ($maxWeight < $weight) { | |
$skip = false; | |
foreach (self::$ownShipsMap as $ownId => $ownShip) { | |
if ($ownId != $this->id && $ownShip->lastTargetId == $id) { | |
$skip = true; | |
break; | |
} | |
} | |
if ($skip) | |
continue; | |
$this->lastTargetId = $id; | |
$minDistance = $crossInfo[0]; | |
error_log(var_export("minDistance:" . $minDistance, true)); | |
$dvx = ($crossInfo[2]); | |
$dvy = ($crossInfo[3]); | |
$maxWeight = $weight; | |
error_log(var_export("id {$this->id}({$this->radius}) njamnjam to {$ship->id}({$ship->radius}) player: {$ship->player}" . $dvx . ' ' . $dvy, true)); | |
} | |
} else { | |
error_log(var_export("id {$this->id}({$this->radius}) njamnjam to {$ship->id}({$ship->radius}) very little", true)); | |
} | |
} else { | |
error_log(var_export("id {$this->id}({$this->radius}) to {$ship->id}({$ship->radius}) long", true)); | |
} | |
} else { | |
error_log(var_export("{$ship->id}({$ship->radius}) die", true)); | |
} | |
} | |
if ($dvx || $dvy) { | |
$px = $this->x + $dvx; | |
if ($px < 0) { | |
$px = 0; | |
} | |
if ($px > self::XSize) { | |
$px = self::XSize; | |
} | |
$py = $this->y + $dvy; | |
if ($py < 0) { | |
$py = 0; | |
} | |
if ($py > self::YSize) { | |
$py = self::YSize; | |
} | |
$act = $px . ' ' . $py; | |
} | |
} | |
return $act; | |
} | |
} | |
$tx = 50; | |
$ty = 50; | |
$vtx = 1; | |
$vty = -1; | |
Ship::$playerId = $playerId; | |
error_log(var_export("coords: ".implode(' ',[$tx,$ty,$vtx,$vty]), true)); | |
Ship::changeCoord($tx,$ty,$vtx,$vty); | |
error_log(var_export("coords: ".implode(' ',[$tx,$ty,$vtx,$vty]), true)); | |
error_log(var_export("dist:".Ship::getDist(50,50,$tx,$ty), true)); | |
// game loop | |
while (TRUE) | |
{ | |
fscanf(STDIN, "%d", | |
$playerChipCount // The number of chips under your control | |
); | |
fscanf(STDIN, "%d", | |
$entityCount // The total number of entities on the table, including your chips | |
); | |
Ship::resetLive(); | |
for ($i = 0; $i < $entityCount; $i++) | |
{ | |
fscanf(STDIN, "%d %d %f %f %f %f %f", | |
$id, // Unique identifier for this entity | |
$player, // The owner of this entity (-1 for neutral droplets) | |
$radius, // the radius of this entity | |
$x, // the X coordinate (0 to 799) | |
$y, // the Y coordinate (0 to 514) | |
$vx, // the speed of this entity along the X axis | |
$vy // the speed of this entity along the Y axis | |
); | |
Ship::updateObject($id,$player,$radius,$x,$y,$vx,$vy); | |
} | |
for ($i = 0; $i < $playerChipCount; $i++) | |
{ | |
// Write an action using echo(). DON'T FORGET THE TRAILING \n | |
// To debug (equivalent to var_dump): error_log(var_export($var, true)); | |
$id = Ship::$ownShips[$i]; | |
$act = Ship::$ownShipsMap[$id]->getAction(); | |
error_log(var_export($act, true)); | |
echo($act."\n"); // One instruction per chip: 2 real numbers (x y) for a propulsion, or 'WAIT'. | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment