mirror of
https://github.com/lscharen/iigs-sprite-compiler.git
synced 2024-10-12 03:23:41 +00:00
90 lines
2.6 KiB
C#
90 lines
2.6 KiB
C#
namespace SpriteCompiler.Problem
|
|
{
|
|
using SpriteCompiler.AI;
|
|
using System.Linq;
|
|
using System;
|
|
|
|
public sealed class SpriteGeneratorHeuristicFunction : IHeuristicFunction<SpriteGeneratorState, IntegerPathCost>
|
|
{
|
|
private static int SpanAndGapCost(int stack, int start, int end, int next)
|
|
{
|
|
var len = end - start + 1;
|
|
|
|
// If the span is within 255 bytes of the stack, there is no
|
|
// gap penalty and we base the cost off of sta xx,s instructions
|
|
|
|
var h1 = SpanAndGapCost(start, end, next);
|
|
var h2 = int.MaxValue;
|
|
|
|
if (stack <= end && (end - stack) < 256)
|
|
{
|
|
h2 = 5 * (len / 2) + 4 * (len % 2);
|
|
}
|
|
|
|
return Math.Min(h1, h2);
|
|
}
|
|
|
|
private static int SpanAndGapCost(int start, int end, int next)
|
|
{
|
|
// [start, end] is the span
|
|
// (end, next) is the gap
|
|
//
|
|
// start <= end <= next
|
|
var len = end - start + 1;
|
|
|
|
// No gap, no penalty
|
|
var gapCost = (end == next) ? 0 : 5;
|
|
var spanCost = 4 * (len / 2) + 3 * (len % 2);
|
|
|
|
return gapCost + spanCost;
|
|
}
|
|
|
|
public IntegerPathCost Eval(SpriteGeneratorState state)
|
|
{
|
|
// An admissible heuistic that calculates a cost based on the gaps and runs in a sprite
|
|
//
|
|
// An even-length run can be done, at best in 4 cycles/word
|
|
// An odd-length run is even + 3 cycles/byte
|
|
|
|
var count = state.Bytes.Count;
|
|
|
|
if (count == 0) return 0;
|
|
|
|
var offsets = state.Bytes.Select(x => x.Offset).OrderBy(x => x).ToList();
|
|
var start = offsets[0];
|
|
var stack = state.S.Value;
|
|
var curr = start;
|
|
var cost = 0;
|
|
|
|
for (int i = 1; i < count; i++)
|
|
{
|
|
var prev = curr;
|
|
curr = offsets[i];
|
|
|
|
if (prev == (curr - 1))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Calculate the estimate cost
|
|
if (state.S.IsScreenOffset)
|
|
{
|
|
cost += SpanAndGapCost(stack, start, prev, curr);
|
|
}
|
|
else
|
|
{
|
|
cost += SpanAndGapCost(start, prev, curr);
|
|
}
|
|
|
|
// Start a new sppan
|
|
start = curr;
|
|
}
|
|
|
|
// End with the span
|
|
cost += SpanAndGapCost(start, curr, curr);
|
|
|
|
return cost;
|
|
}
|
|
}
|
|
}
|