Commit 512744e9 authored by Hubert Denkmair's avatar Hubert Denkmair
Browse files

implement BotMoveHead strategy!

parent 3c669984
BotMoveHeadMoveStrategy = function()
{
this.WORLD_SIZE_X = 0;
this.WORLD_SIZE_Y = 0;
this.WORLD_RADIUS_X = 0;
this.WORLD_RADIUS_Y = 0;
this.DISTANCE_PER_STEP = 1.0;
this.SEGMENT_DISTANCE_FACTOR = 0.2;
this.SEGMENT_DISTANCE_EXPONENT = 0.3;
this.PULL_FACTOR = 0.1;
};
BotMoveHeadMoveStrategy.prototype.SetGameInfo = function(gameinfo)
{
this.gameinfo = gameinfo;
this.WORLD_SIZE_X = gameinfo.world_size_x;
this.WORLD_SIZE_Y = gameinfo.world_size_y;
this.WORLD_RADIUS_X = gameinfo.world_size_x/2;
this.WORLD_RADIUS_Y = gameinfo.world_size_y/2;
this.DISTANCE_PER_STEP = gameinfo.snake_distance_per_step;
this.SEGMENT_DISTANCE_FACTOR = gameinfo.snake_segment_distance_factor;
this.SEGMENT_DISTANCE_EXPONENT = gameinfo.snake_segment_distance_exponent;
this.PULL_FACTOR = gameinfo.snake_pull_factor;
};
BotMoveHeadMoveStrategy.prototype.WrapCoords = function(v)
{
let x = v.x;
let y = v.y;
while (x < 0) { x += this.WORLD_SIZE_X; }
while (x > this.WORLD_SIZE_X) { x -= this.WORLD_SIZE_X; }
while (y < 0) { y += this.WORLD_SIZE_Y; }
while (y > this.WORLD_SIZE_Y) { y -= this.WORLD_SIZE_Y; }
return [x, y];
}
BotMoveHeadMoveStrategy.prototype.UnwrapCoords = function(v, ref)
{
let x = v.x;
let y = v.y;
while ((x - ref.x) < -this.WORLD_RADIUS_X) { x += this.WORLD_SIZE_X; }
while ((x - ref.x) > this.WORLD_RADIUS_X) { x -= this.WORLD_SIZE_X; }
while ((y - ref.y) < -this.WORLD_RADIUS_Y) { y += this.WORLD_SIZE_Y; }
while ((y - ref.y) > this.WORLD_RADIUS_Y) { y -= this.WORLD_SIZE_Y; }
return [x, y];
};
BotMoveHeadMoveStrategy.prototype.GetTargetSegmentDistance = function(mass)
{
return Math.pow(mass * this.SEGMENT_DISTANCE_FACTOR, this.SEGMENT_DISTANCE_EXPONENT);
};
BotMoveHeadMoveStrategy.prototype.NewStyleMove = function(bot, mass, positions)
{
if (!bot._movedSinceLastSpawn) { bot._movedSinceLastSpawn = 0; }
if (bot.GetLength() < 2) { return; } // FIXME should this be possible? happens all the time!
const targetSegmentDistance = this.GetTargetSegmentDistance(mass);
const targetLength = Math.max(mass / targetSegmentDistance / 5, 2);
/* unwrap coordinates */
for (let i=0; i<bot.GetLength(); i++)
{
let seg = bot.GetSegment(i);
let coords = this.UnwrapCoords(seg, bot.GetSegment((i==0) ? 0 : i-1));
seg.SetPosition(coords[0], coords[1]);
}
for (let pos of positions)
{
let head = bot.GetSegment(0);
head.x = pos[0];
head.y = pos[1];
bot._movedSinceLastSpawn += this.DISTANCE_PER_STEP;
while (bot._movedSinceLastSpawn > targetSegmentDistance)
{
let head = bot.GetSegment(0);
let second = bot.GetSegment(1);
let offset_x = head.x - second.x;
let offset_y = head.y - second.y;
const offset_dist = Math.sqrt(offset_x*offset_x + offset_y*offset_y);
const offset_factor = targetSegmentDistance / offset_dist;
offset_x *= offset_factor;
offset_y *= offset_factor;
bot._movedSinceLastSpawn -= targetSegmentDistance;
bot.InsertSegmentAfterHead(second.x+offset_x, second.y+offset_y);
}
}
/* pull together */
for (let i=1; i<bot.GetLength()-1; i++)
{
let prevSegment = bot.GetSegment(i-1);
let segment = bot.GetSegment(i);
let nextSegment = bot.GetSegment(i+1);
const new_x = segment.x * (1 - this.PULL_FACTOR) + (0.5*nextSegment.x + 0.5*prevSegment.x) * this.PULL_FACTOR;
const new_y = segment.y * (1 - this.PULL_FACTOR) + (0.5*nextSegment.y + 0.5*prevSegment.y) * this.PULL_FACTOR;
segment.SetPosition(new_x, new_y);
}
/* wrap coordinates */
for (let i=0; i<bot.GetLength(); i++)
{
let seg = bot.GetSegment(i);
let coords = this.WrapCoords(seg);
seg.SetPosition(coords[0], coords[1]);
}
bot.SetLength(targetLength);
bot.SetScale(Math.sqrt(mass) / 2);
bot.UpdateHead();
};
BotMoveHeadMoveStrategy.prototype.OldStyleMove = function(bot, new_segments, new_length, current_segment_radius)
{
};
DynamicSegmentCountSnakeMoveStrategy = function()
{
};
DynamicSegmentCountSnakeMoveStrategy.prototype.NewStyleMove = function(bot, heading, speed, length, segment_radius)
{
bot.heading = heading;
bot.speed = speed;
bot.SetScale(segment_radius);
let num_segments = Math.floor(20 + length * 0.1);
let target_distance = (length / (num_segments - 1));
bot.SetLength(num_segments);
bot.GetSegment(0).MoveDirection(bot.heading, bot.speed);
for (let i=1; i<bot.GetLength(); i++)
{
let pred = bot.GetSegment(i-1);
let seg = bot.GetSegment(i);
let dx = seg.x - pred.x;
let dy = seg.y - pred.y;
let scale = target_distance / Math.sqrt(dx*dx + dy*dy);
seg.SetPosition(pred.x + dx*scale, pred.y + dy*scale);
}
};
DynamicSegmentCountSnakeMoveStrategy.prototype.OldStyleMove = function(bot, new_segments, new_length, current_segment_radius)
{
};
DynamicSegmentCountSnakeMoveStrategy.prototype.Wrap = function(value)
{
if (value < -512)
{
return value + 1024;
}
else if (value > 512)
{
return value - 1024;
}
else
{
return value;
}
};
\ No newline at end of file
......@@ -6,6 +6,7 @@ function Game(assets, snakeMoveStrategy, container)
this.heading = 0;
this.speed = 2;
this.viewer_key = 0;
this.snakeMoveStrategy = snakeMoveStrategy;
this.vis = new GameVisualization(assets, snakeMoveStrategy, container);
this.logHandlers = [];
this.gameInfoReceived = false;
......@@ -63,6 +64,10 @@ Game.prototype.HandleMessage = function(event)
if (data.t == "GameInfo")
{
this.gameInfoReceived = true;
if (this.snakeMoveStrategy.SetGameInfo)
{
this.snakeMoveStrategy.SetGameInfo(data);
}
this.vis.HandleGameInfoMessage(data.world_size_x, data.world_size_y, data.food_decay_per_frame);
while (this.preGameInfoMessages.length > 0)
{
......@@ -95,13 +100,17 @@ Game.prototype.HandleMessage = function(event)
let b = data.items[i];
this.vis.HandleBotMovedMessage(b.bot_id, b.segment_data, b.length, b.segment_radius);
}
return this.vis.HandleTickMessage(null); // FIXME this is a workaround because we somehow do not receive TickMessage
return;
case "BotStats":
this.HandleBotStatsMessage(data.data);
return;
case "BotMoveHead":
for (let bot of data.items)
{
this.vis.HandleBotMoveHeadMessage(bot.bot_id, bot.m, bot.p);
}
return;
case "FoodSpawn":
......
......@@ -230,12 +230,11 @@ GameVisualization.prototype.HandleBotMovedMessage = function(bot_id, segment_dat
}
};
GameVisualization.prototype.HandleBotMoved2Message = function(bot_id, heading, speed, length, segment_radius)
GameVisualization.prototype.HandleBotMoveHeadMessage = function(bot_id, mass, positions)
{
if (bot_id in this.snakes)
{
this.snakeMoveStrategy.NewStyleMove(this.snakes[bot_id], heading, speed, length, segment_radius);
this.snakes[bot_id].UpdateHead();
this.snakeMoveStrategy.NewStyleMove(this.snakes[bot_id], mass, positions);
}
};
......
ImpulseSnakeMoveStrategy = function()
{
};
ImpulseSnakeMoveStrategy.prototype.NewStyleMove = function(bot, heading, speed, length, segment_radius)
{
bot.heading = heading;
bot.speed = speed;
bot.SetLength(Math.floor(length));
bot.SetScale(segment_radius);
let factor_pred = 0.9;
let factor_impulse = 1 - factor_pred;
for (let i=bot.GetLength()-1; i>0; i--)
{
let succ = bot.GetSegment(i);
let pred = bot.GetSegment(i-1);
let dx = pred.x - succ.x;
let dy = pred.y - succ.y;
if (!succ.last_dx) { succ.last_dx = dx; }
if (!succ.last_dy) { succ.last_dy = dy; }
dx = factor_pred*dx + factor_impulse * succ.last_dx;
dy = factor_pred*dy + factor_impulse * succ.last_dy;
succ.last_dx = dx;
succ.last_dy = dy;
succ.SetPosition(succ.x+dx, succ.y+dy);
}
bot.GetSegment(0).MoveDirection(bot.heading, bot.speed);
};
ImpulseSnakeMoveStrategy.prototype.OldStyleMove = function(bot, new_segments, new_length, current_segment_radius)
{
};
......@@ -2,18 +2,8 @@ SimpleDirectionSnakeMoveStrategy = function()
{
};
SimpleDirectionSnakeMoveStrategy.prototype.NewStyleMove = function(bot, heading, speed, length, segment_radius)
SimpleDirectionSnakeMoveStrategy.prototype.NewStyleMove = function(bot, mass, positions)
{
bot.heading = heading;
bot.speed = speed;
bot.SetLength(Math.floor(length));
bot.SetScale(segment_radius);
for (let i=bot.GetLength()-1; i>0; i--)
{
bot.GetSegment(i).ClonePosition(bot.GetSegment(i-1));
}
bot.GetSegment(0).MoveDirection(bot.heading, bot.speed);
};
SimpleDirectionSnakeMoveStrategy.prototype.OldStyleMove = function(bot, new_segments, new_length, current_segment_radius)
......
......@@ -172,11 +172,18 @@ Snake.prototype.GetName = function()
Snake.prototype.UpdateHead = function()
{
let seg0 = this.GetSegment(0);
let seg1 = this.GetSegment(1);
this.heading = Math.atan2(seg0.y - seg1.y, seg0.x - seg1.x);
this._headSegment.ClonePosition(seg0);
this._headSegment.SetRotation(this.heading);
this._nameSprite.x = seg0.x;
this._nameSprite.y = seg0.y;
}
for (let i=0; i<this.GetLength(); i++)
{
this.GetSegment(i).SetTint(this._colorScheme[i % this._colorScheme.length]);
}
};
Snake.prototype.CalcRealLength = function()
{
......@@ -223,4 +230,14 @@ Snake.prototype.AnimateEat = function()
food.y = y + dy*factor;
food.speed *= 1.3;
}
};
\ No newline at end of file
};
Snake.prototype.InsertSegmentAfterHead = function(x, y)
{
let segment = this._segmentPool.get();
segment.SetPosition(x, y);
segment.SetWorldSize(this.world_size_x, this.world_size_y);
segment.SetScale(this.spriteScale);
segment.AddSpritesSecond(this._segmentContainer);
this._segments.splice(1, 0, segment);
}
\ No newline at end of file
......@@ -46,6 +46,14 @@ SnakeSegment.prototype.AddSpritesFront = function(container)
}
};
SnakeSegment.prototype.AddSpritesSecond = function(container)
{
for (let sprite of this._sprites)
{
container.addChildAt(sprite, container.children.length-2);
}
};
SnakeSegment.prototype.RemoveSprites = function()
{
for (let sprite of this._sprites)
......
TwoPredecessorSnakeMoveStrategy = function()
{
};
TwoPredecessorSnakeMoveStrategy.prototype.NewStyleMove = function(bot, heading, speed, length, segment_radius)
{
bot.heading = heading;
bot.speed = speed;
bot.SetLength(Math.floor(length));
bot.SetScale(segment_radius);
let factor_pred1 = 0;
let factor_pred2 = (1 - factor_pred1) / 2;
for (let i=bot.GetLength()-1; i>0; i--)
{
let me = bot.GetSegment(i);
let pred1 = bot.GetSegment(i-1);
let dx1 = pred1.x - me.x;
let dy1 = pred1.y - me.y;
let dx2 = dx1;
let dy2 = dy1;
if (i>1)
{
let pred2 = bot.GetSegment(i-2);
dx2 = pred2.x - me.x;
dy2 = pred2.y - me.y;
}
if (dx1 < -512) { dx1 += 1024; }
if (dx2 < -512) { dx2 += 1024; }
if (dy1 < -512) { dy1 += 1024; }
if (dy2 < -512) { dy2 += 1024; }
if (dx1 > +512) { dx1 -= 1024; }
if (dx2 > +512) { dx2 -= 1024; }
if (dy1 > +512) { dy1 -= 1024; }
if (dy2 > +512) { dy2 -= 1024; }
let dx = factor_pred1*dx1 + factor_pred2 * dx2;
let dy = factor_pred1*dy1 + factor_pred2 * dy2;
me.SetPosition(me.x+dx, me.y+dy);
}
bot.GetSegment(0).MoveDirection(bot.heading, bot.speed);
};
TwoPredecessorSnakeMoveStrategy.prototype.OldStyleMove = function(bot, new_segments, new_length, current_segment_radius)
{
};
......@@ -7,6 +7,7 @@
<script src="{% static "visualization/Snake.js" %}"></script>
<script src="{% static "visualization/FoodSprite.js" %}"></script>
<script src="{% static "visualization/SimpleDirectionSnakeMoveStrategy.js" %}"></script>
<script src="{% static "visualization/BotMoveHeadMoveStrategy.js" %}"></script>
<script src="{% static "visualization/GameVisualization.js" %}"></script>
<script src="{% static "visualization/Game.js" %}"></script>
<script>
......@@ -15,8 +16,6 @@
'food.png': '{% static "visualization/assets/food.png" %}',
'head.png': '{% static "visualization/assets/head.png" %}',
};
let strategy = new SimpleDirectionSnakeMoveStrategy();
//let strategy = new ImpulseSnakeMoveStrategy();
//let strategy = new TwoPredecessorSnakeMoveStrategy();
//let strategy = new DynamicSegmentCountSnakeMoveStrategy();
//let strategy = new SimpleDirectionSnakeMoveStrategy();
let strategy = new BotMoveHeadMoveStrategy();
</script>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment