public PositionTable <double> Solve(Story story) { DateTime time = DateTime.Now; //IPermutationCalculator permCalculator = new LocationSensitiveCalculator(); IPermutationCalculator permCalculator = new LocationTreeCalculator(); PositionTable <int> perm = permCalculator.Calculate(story); Console.WriteLine(">>>Perm Time Consuming:{0}", DateTime.Now - time); time = DateTime.Now; IAligner aligner = new LocationTreeAligner(_app); PositionTable <int> segments = aligner.Align(story, perm); Console.WriteLine(">>>Align Time Consuming:{0}", DateTime.Now - time); time = DateTime.Now; _app.Status.Optimizer = new GreedyOptimizer(_app.Status.Config, story, perm, segments); PositionTable <double> position = _app.Status.Optimizer.Optimize(); Console.WriteLine(">>>Optimize Time Consuming:{0}", DateTime.Now - time); time = DateTime.Now; // move to positive double min = int.MaxValue; for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1 && min > position[id, frame]) { min = position[id, frame]; } } } for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1) { position[id, frame] -= min; position[id, frame] *= 1; } } } Console.WriteLine("Location Tree Crossing:{0}", Crossing.Count(story, perm)); return(position); }
public PositionTable <double> Solve(Story story) { IPermutationCalculator permCalculator = new LocationSensitiveCalculator(); PositionTable <int> perm = permCalculator.Calculate(story); //for (int i = 0; i < story.Characters.Count; ++i) //{ // for (int j = 0; j < story.FrameCount; ++j) // Console.Write(perm[i, j] + ", "); // Console.WriteLine(); //} IAligner aligner = new LocationSensitiveAligner(); PositionTable <int> segments = aligner.Align(story, perm); PositionTable <double> position = perm.Clone <double>(); LongLineConstrainedOptimizer optimizer = new LongLineConstrainedOptimizer(_app); optimizer.Optimize(story, position, segments); // move to positive double min = int.MaxValue; for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1 && min > position[id, frame]) { min = position[id, frame]; } } } for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1) { position[id, frame] -= min; position[id, frame] *= 1; } } } Console.WriteLine("Location Sensitive Crossing:{0}", Crossing.Count(story, perm)); return(position); }
public PositionTable <double> Solve(Story story) { int outerGap = (int)(_app.Status.Config.Style.OuterGap / _app.Status.Config.Style.DefaultInnerGap); PositionTable <int> positionTable = new PositionTable <int>(story.Characters.Count, story.TimeStamps.Length - 1); // 1.put first frame List <Tuple <int, List <int> > > list = Ultities.GetGroups(story, 0); //List<Tuple<int, List<int>>> list = Ultities.GetRandomList<Tuple<int, List<int>>>(Ultities.GetGroups(story, 0)); int yBaseline = 0; foreach (Tuple <int, List <int> > tuple in list) { foreach (int id in tuple.Item2) { positionTable[id, 0] = yBaseline; yBaseline += 1; } yBaseline += outerGap; } // 2.calculate group average for other frames for (int frame = 1; frame < story.TimeStamps.Length - 1; ++frame) { list = Ultities.GetGroups(story, frame); list.Sort((a, b) => - a.Item2.Count.CompareTo(b.Item2.Count)); List <int> occupied = new List <int>(); foreach (Tuple <int, List <int> > tuple in list) { // sort by previous position tuple.Item2.Sort((a, b) => positionTable[a, frame - 1].CompareTo(positionTable[b, frame - 1])); // calculate weighted average position int weight = 0; int value = 0; int sub = 0; bool allNew = true; foreach (int id in tuple.Item2) { if (story.SessionTable[id, frame - 1] != -1) { allNew = false; break; } } int top; if (allNew) { top = 0 - tuple.Item2.Count / 2; } else { for (int i = 0; i < tuple.Item2.Count; ++i) { int id = tuple.Item2[i]; int w = Ultities.GetHistoryLength(story, id, frame); value += w * positionTable[id, frame - 1]; weight += w; sub += w * i; } double bestCenter = (double)value / weight; top = (int)Math.Round((bestCenter * weight - sub) / weight); } // find a place to put it for (int shift = 0; true; ++shift) { int shiftedTop1 = top - shift; int shiftedTop2 = top + shift; bool available = false; int pos = 0; if (IsAvailable(occupied, shiftedTop1 - outerGap, shiftedTop1 + tuple.Item2.Count - 1 + outerGap)) { pos = shiftedTop1; available = true; } else if (IsAvailable(occupied, shiftedTop2 - outerGap, shiftedTop2 + tuple.Item2.Count - 1 + outerGap)) { pos = shiftedTop2; available = true; } if (available) { for (int i = 0; i < tuple.Item2.Count; ++i) { positionTable[tuple.Item2[i], frame] = pos + i; occupied.Add(pos + i); } break; } } } } for (int t = 0; t < 10; ++t) { // shift lines to new positions for (int frame = 1; frame < story.TimeStamps.Length - 2; ++frame) { HashSet <int> deltas = new HashSet <int>(); for (int id = 0; id < story.Characters.Count; ++id) { if (story.SessionTable[id, frame] != -1 && story.SessionTable[id, frame + 1] != -1) { int delta = positionTable[id, frame] - positionTable[id, frame + 1]; if (!deltas.Contains(delta)) { deltas.Add(delta); } } } int minCost = int.MaxValue; int minDelta = 0; foreach (int delta in deltas) { int cost = 0; for (int id = 0; id < story.Characters.Count; ++id) { if (story.SessionTable[id, frame] != -1 && story.SessionTable[id, frame + 1] != -1) { cost += Math.Abs(positionTable[id, frame + 1] + delta - positionTable[id, frame]); if (positionTable[id, frame + 1] + delta == positionTable[id, frame]) { cost -= 100; } } } if (minCost > cost) { minCost = cost; minDelta = delta; } } for (int id = 0; id < story.Characters.Count; ++id) { positionTable[id, frame + 1] += minDelta; } } for (int frame = 1; frame < story.TimeStamps.Length - 2; ++frame) { for (int id = 0; id < story.Characters.Count; ++id) { if (Ultities.GetGroupCount(story, id, frame) == 1 && Ultities.GetGroupCount(story, id, frame + 1) > 1) { bool isHead = true; int f; for (f = frame - 1; f >= 0; --f) { if (Ultities.GetGroupCount(story, id, f) > 1) { isHead = false; break; } else if (story.SessionTable[id, f] == -1) { break; } } //if (!isHead) // continue; //positionTable[id, frame] = -100; //continue; // HashSet <int> tubes = new HashSet <int>(); for (int ii = f + 1; ii <= frame; ++ii) { for (int ch = 0; ch < story.Characters.Count; ++ch) { if (ch != id && story.SessionTable[ch, ii] != -1) { if (!tubes.Contains(positionTable[ch, ii])) { tubes.Add(positionTable[ch, ii]); } } } } var occupied = tubes.ToList <int>(); int p = positionTable[id, frame + 1]; // find a place to put it for (int shift = 0; true; ++shift) { int shiftedTop1 = p - shift; int shiftedTop2 = p + shift; bool available = false; int pp = 0; if (IsAvailable(occupied, shiftedTop1 - outerGap, shiftedTop1 + outerGap)) { pp = shiftedTop1; available = true; } else if (IsAvailable(occupied, shiftedTop2 - outerGap, shiftedTop2 + outerGap)) { pp = shiftedTop2; available = true; } if (available) { for (int ii = f + 1; ii <= frame; ++ii) { //if (Math.Abs(positionTable[id, ii] - pp) > 0) { positionTable[id, ii] = pp; } } break; } } } } } // } PositionTable <double> position = positionTable.Clone <double>(); Debug.WriteLine("Before, Crossing:{0}", Crossing.Count(story, position.Clone <int>())); PositionOptimizer3 optimizer2 = new PositionOptimizer3(); position = optimizer2.Optimize(story, position, 0.4, 0.9, 0.0, 0.0); position = optimizer2.Optimize(story, position, 0.9, 0.9, 0.0, 0.0); PositionOptimizer2 optimizer = new PositionOptimizer2(); position = optimizer.Optimize(story, position, 0.4, 0.5, 0.0, 0.0); position = optimizer2.Optimize(story, position, 0.4, 0.9, 0.0, 0.0); //position = optimizer2.Optimize(story, position, 1.0, 0.1, 0.0, 0.0); //position = optimizer.Optimize(story, position, 1.0, 0.1, 0.0, 0.0); PositionOptimizer1 optimizer1 = new PositionOptimizer1(); //position = optimizer1.Optimize(story, position); int x = 4; while (x-- > 0) { //position = optimizer.Optimize(story, position, 0.6, 0.2, 0.0, 0.0); position = optimizer2.Optimize(story, position, 1.0, 0.5, 0.0, 0.0); position = optimizer1.Optimize(story, position); } // move to positive double min = 0; for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1 && min > position[id, frame]) { min = position[id, frame]; } } } for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1) { position[id, frame] -= min; position[id, frame] *= 5; } } } Debug.WriteLine("Crossing:{0}", Crossing.Count(story, position.Clone <int>())); return(position); positionTable = position.Clone <int>(); int[,] permutationTable = new int[story.Characters.Count, story.TimeStamps.Length - 1]; { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { List <Tuple <int, int> > l = new List <Tuple <int, int> >(); for (int id = 0; id < story.Characters.Count; ++id) { if (story.SessionTable[id, frame] != -1) { l.Add(new Tuple <int, int>(id, positionTable[id, frame])); } else { l.Add(new Tuple <int, int>(id, 100000)); } } l.Sort((a, b) => a.Item2.CompareTo(b.Item2)); for (int i = 0; i < l.Count; ++i) { permutationTable[l[i].Item1, frame] = i; } } // calculate positions PositionTable <int> posY = new PositionTable <int>(story.Characters.Count, story.TimeStamps.Length - 1); List <int[]>[] intervals = new List <int[]> [story.TimeStamps.Length - 1]; List <int>[] prev = new List <int> [story.TimeStamps.Length - 1]; List <int>[] next = new List <int> [story.TimeStamps.Length - 1]; List <Tuple <int, int, int> >[] lcss = new List <Tuple <int, int, int> > [story.TimeStamps.Length - 1]; for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { // find intervals at this frame int[] t = new int[story.Characters.Count]; for (int i = 0; i < story.Characters.Count; ++i) { t[permutationTable[i, frame]] = i; } List <int> p = new List <int>(); for (int i = 0; i < t.Length; ++i) { if (story.SessionTable[t[i], frame] != -1) { p.Add(t[i]); } } intervals[frame] = new List <int[]>(); prev[frame] = new List <int>(); next[frame] = new List <int>(); lcss[frame] = new List <Tuple <int, int, int> >(); int last = -1; for (int i = 0; i < p.Count; ++i) { if (i == p.Count - 1 || story.SessionTable[p[i], frame] != story.SessionTable[p[i + 1], frame]) { intervals[frame].Add(p.GetRange(last + 1, i - last).ToArray <int>()); last = i; prev[frame].Add(-1); next[frame].Add(-1); lcss[frame].Add(new Tuple <int, int, int>(-1, -1, -1)); } } // calculate the connection with previous frame if (frame > 0) { Tuple <int, int, int>[,] lcs = new Tuple <int, int, int> [intervals[frame - 1].Count, intervals[frame].Count]; for (int i = 0; i < intervals[frame - 1].Count; ++i) { for (int j = 0; j < intervals[frame].Count; ++j) { lcs[i, j] = GetLcs(intervals[frame - 1][i], intervals[frame][j]); } } int[,] dp = new int[intervals[frame - 1].Count + 1, intervals[frame].Count + 1]; Tuple <int, int>[,] path = new Tuple <int, int> [intervals[frame - 1].Count + 1, intervals[frame].Count + 1]; for (int i = 0; i < intervals[frame - 1].Count; ++i) { for (int j = 0; j < intervals[frame].Count; ++j) { dp[i + 1, j + 1] = -1; if (dp[i + 1, j + 1] < dp[i, j] + lcs[i, j].Item3) { dp[i + 1, j + 1] = dp[i, j] + lcs[i, j].Item3; path[i + 1, j + 1] = new Tuple <int, int>(i, j); } if (dp[i + 1, j + 1] < dp[i + 1, j]) { dp[i + 1, j + 1] = dp[i + 1, j]; path[i + 1, j + 1] = new Tuple <int, int>(i + 1, j); } if (dp[i + 1, j + 1] < dp[i, j + 1]) { dp[i + 1, j + 1] = dp[i, j + 1]; path[i + 1, j + 1] = new Tuple <int, int>(i, j + 1); } } } { int i = intervals[frame - 1].Count - 1; int j = intervals[frame].Count - 1; while (i > -1 && j > -1) { if (path[i + 1, j + 1].Item1 == i && path[i + 1, j + 1].Item2 == j) { prev[frame][j] = i; next[frame - 1][i] = j; lcss[frame][j] = lcs[i, j]; } Tuple <int, int> pair = path[i + 1, j + 1]; i = pair.Item1 - 1; j = pair.Item2 - 1; } } } } int[] top = new int[story.TimeStamps.Length - 1]; List <List <Tuple <int, int> > > layers = new List <List <Tuple <int, int> > >(); while (true) { bool[] isAtTop = new bool[story.TimeStamps.Length - 1]; bool exist = false; for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { // now calculate a bool of isAtTop[frame] if (top[frame] >= intervals[frame].Count) // this frame is already empty { continue; } exist = true; bool flag = true; int current = prev[frame][top[frame]]; int currentFrame = frame - 1; while (current > -1) { if (top[currentFrame] != current) { flag = false; break; } current = prev[currentFrame][current]; --currentFrame; } current = next[frame][top[frame]]; currentFrame = frame + 1; while (current > -1) { if (top[currentFrame] != current) { flag = false; break; } current = next[currentFrame][current]; ++currentFrame; } isAtTop[frame] = flag; } if (!exist) { break; } layers.Add(new List <Tuple <int, int> >()); var layer = layers.Last <List <Tuple <int, int> > >(); for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (isAtTop[frame]) { layer.Add(new Tuple <int, int>(frame, top[frame])); ++top[frame]; } } } //Point[,] positions = new Point[permutation.FrameCount, permutation.CharacterCount]; //double[,] posY = new double[frameCount, characterCount]; int yBaseline1 = 0; int minY = int.MaxValue; int maxY = int.MinValue; for (int i = 0; i < layers.Count; ++i) { List <Tuple <int, int> > layer = layers[i]; int[] topY = new int[layer.Count]; int[] bottomY = new int[layer.Count]; int lastTopY = -100000; minY = int.MaxValue; maxY = int.MinValue; for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; if (prev[frame][k] == -1) { topY[j] = 0; lastTopY = 0; } else { topY[j] = lastTopY - lcss[frame][k].Item2 + lcss[frame][k].Item1; lastTopY = topY[j]; } if (minY > topY[j]) { minY = topY[j]; } } for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; topY[j] -= minY; bottomY[j] = topY[j] + intervals[frame][k].Length; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; posY[character, frame] = yBaseline1 + (topY[j] + ii) * (int)_app.Status.Config.Style.DefaultInnerGap; //positions[frame, character] = new Point(frame * styles.TimeScaleFactor, baseline + (topY[j] + ii) * styles.InnerDistance); if (maxY < posY[character, frame]) { maxY = (int)posY[character, frame]; } } } yBaseline1 = maxY + (int)_app.Status.Config.Style.OuterGap; } { // new added, move down the hanging lines from bottom lay to top bool[,] rearranged = new bool[story.Characters.Count, story.TimeStamps.Length - 1]; int[] topOfFrame = new int[story.TimeStamps.Length - 1]; for (int i = 0; i < topOfFrame.Length; ++i) { topOfFrame[i] = maxY; } for (int i = layers.Count - 1; i >= 0; --i) { List <Tuple <int, int> > layer = layers[i]; if (i != layers.Count - 1) // this is not the bottom layer { int minDepth = int.MaxValue; int BottomOfPiece = 0; int TopOfPieceGround = 0; List <Tuple <int, int> > stack = new List <Tuple <int, int> >(); for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; int max = int.MinValue; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; if (max < posY[character, frame]) { max = posY[character, frame]; } } if (prev[frame][k] == -1) { BottomOfPiece = max; TopOfPieceGround = topOfFrame[frame]; stack.Clear(); stack.Add(new Tuple <int, int>(frame, k)); if (intervals[frame][k].Length == 1 && (frame > 0 && story.SessionTable[intervals[frame][k][0], frame - 1] == -1)) { int pos = posY[intervals[frame][k][0], frame]; int f = frame; do { ++f; }while (f < story.TimeStamps.Length - 1 && posY[intervals[frame][k][0], f] == pos); if (f != story.TimeStamps.Length - 1) { HashSet <int> tubes = new HashSet <int>(); for (int ii = frame; ii < f; ++ii) { for (int ch = 0; ch < story.Characters.Count; ++ch) { if (ch != intervals[frame][k][0]) { if (!tubes.Contains(posY[ch, ii])) { tubes.Add(posY[ch, ii]); } } } } var occupied = tubes.ToList <int>(); int p = posY[intervals[frame][k][0], f]; // find a place to put it for (int shift = 0; true; ++shift) { int shiftedTop1 = p - shift; int shiftedTop2 = p + shift; bool available = false; int pp = 0; if (IsAvailable(occupied, shiftedTop1 - (int)_app.Status.Config.Style.OuterGap, shiftedTop1 + (int)_app.Status.Config.Style.OuterGap)) { pp = shiftedTop1; available = true; } else if (IsAvailable(occupied, shiftedTop2 - (int)_app.Status.Config.Style.OuterGap, shiftedTop2 + (int)_app.Status.Config.Style.OuterGap)) { pp = shiftedTop2; available = true; } if (available) { for (int ii = frame; ii < f; ++ii) { if (Math.Abs(posY[intervals[frame][k][0], ii] - pp) > 0) { posY[intervals[frame][k][0], ii] = pp; rearranged[intervals[frame][k][0], ii] = true; } } break; } } } } } else { if (BottomOfPiece < max) { BottomOfPiece = max; } if (TopOfPieceGround > topOfFrame[frame]) { TopOfPieceGround = topOfFrame[frame]; } stack.Add(new Tuple <int, int>(frame, k)); } if (next[frame][k] == -1) { if (TopOfPieceGround - BottomOfPiece > (int)_app.Status.Config.Style.OuterGap * 2 - 1) { // a large gap detected int delta = TopOfPieceGround - BottomOfPiece - (int)_app.Status.Config.Style.OuterGap; int up = 0; int down = 0; foreach (Tuple <int, int> tuple in stack) { int f = tuple.Item1; int kk = tuple.Item2; for (int jj = 0; jj < intervals[f][kk].Length; ++jj) { int ch = intervals[f][kk][jj]; if (f < story.TimeStamps.Length - 1 - 1) { if (story.SessionTable[ch, f + 1] != -1) { if (posY[ch, f] > posY[ch, f + 1]) { ++up; } else if (posY[ch, f] < posY[ch, f + 1]) { ++down; } } } if (f > 0) { if (story.SessionTable[ch, f - 1] != -1) { if (posY[ch, f] > posY[ch, f - 1]) { ++up; } else if (posY[ch, f] < posY[ch, f - 1]) { ++down; } } } } } if (down >= up) { foreach (Tuple <int, int> tuple in stack) { int f = tuple.Item1; int kk = tuple.Item2; for (int ii = 0; ii < intervals[f][kk].Length; ++ii) { int character = intervals[f][kk][ii]; if (!rearranged[character, f]) { posY[character, f] += delta; } } } } } } } } for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; if (topOfFrame[frame] > posY[character, frame]) { topOfFrame[frame] = posY[character, frame]; } } } } // over } return(posY.Clone <double>()); } }
public PositionTable <double> Solve(Story story) { //IPermutationCalculator permCalculator = new EfficientBarycenterCalculator(); IPermutationCalculator permCalculator = new CrossingMinimizedCalculator(); PositionTable <int> perm = permCalculator.Calculate(story); PositionTable <double> position = new PositionTable <double>(story.Characters.Count, story.TimeStamps.Length - 1); // transfer perm to position position = perm.Clone <double>(); // new potimize ShortLineConstrainedOptimizer2 opt = new ShortLineConstrainedOptimizer2(); opt.Optimize(story, position); // optimize Debug.WriteLine("Before opt, Crossing:{0}", Crossing.Count(story, position.Clone <int>())); PositionOptimizer3 optimizer2 = new PositionOptimizer3(); PositionOptimizer1 optimizer1 = new PositionOptimizer1(); PositionOptimizer2 optimizer = new PositionOptimizer2(); int x = 0; while (x-- > 0) { //position = optimizer.Optimize(story, position, 0.6, 0.2, 0.0, 0.0); position = optimizer2.Optimize(story, position, 1.0, 0.5, 0.0, 0.0); position = optimizer1.Optimize(story, position, 1.0, 0.0, 0.0, 0.0); } Debug.WriteLine("After opt, Crossing:{0}", Crossing.Count(story, position.Clone <int>())); // move to positive double min = 0; for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1 && min > position[id, frame]) { min = position[id, frame]; } } } for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1) { position[id, frame] -= min; position[id, frame] *= 1; } } } return(position); }
public PositionTable <double> Solve(Story story) { int frameCount = story.TimeStamps.Length - 1; int characterCount = story.Characters.Count; int[,] permutaion = new int[characterCount, frameCount]; { List <int[]>[] states = new List <int[]> [frameCount]; List <int>[] dp = new List <int> [frameCount]; List <int>[] path = new List <int> [frameCount]; int[] orderedSequence = new int[characterCount]; for (int i = 0; i < characterCount; ++i) { orderedSequence[i] = i; } for (int frame = 0; frame < frameCount; ++frame) { states[frame] = new List <int[]>(); dp[frame] = new List <int>(); path[frame] = new List <int>(); int[] permutation = (int[])orderedSequence.Clone(); do { if (IsValidPermutation(permutation, story.SessionTable, frame)) { states[frame].Add((int[])permutation.Clone()); } }while (NextPermutation <int>(permutation)); for (int i = 0; i < states[frame].Count; ++i) { if (frame == 0) { dp[frame].Add(0); path[frame].Add(0); } else { int min = int.MaxValue; int from = -1; for (int j = 0; j < states[frame - 1].Count; ++j) { int d = dp[frame - 1][j] + GetCost(states[frame - 1][j], states[frame][i], story.SessionTable, frame); if (d < min) { min = d; from = j; } } dp[frame].Add(min); path[frame].Add(from); } } } // int cost = int.MaxValue; int index = -1; int count = 0; for (int i = 0; i < dp[frameCount - 1].Count; ++i) { if (cost > dp[frameCount - 1][i]) { cost = dp[frameCount - 1][i]; index = i; count = 1; } else if (cost == dp[frameCount - 1][i]) { ++count; } } for (int frame = frameCount - 1; frame > -1; --frame) { for (int id = 0; id < characterCount; ++id) { permutaion[id, frame] = states[frame][index][id]; } index = path[frame][index]; } } // calculate positions PositionTable <int> posY = new PositionTable <int>(characterCount, frameCount); { List <int[]>[] intervals = new List <int[]> [frameCount]; List <int>[] prev = new List <int> [frameCount]; List <int>[] next = new List <int> [frameCount]; List <Tuple <int, int, int> >[] lcss = new List <Tuple <int, int, int> > [frameCount]; for (int frame = 0; frame < frameCount; ++frame) { // find intervals at this frame int[] t = new int[characterCount]; for (int i = 0; i < characterCount; ++i) { t[permutaion[i, frame]] = i; } List <int> p = new List <int>(); for (int i = 0; i < t.Length; ++i) { if (story.SessionTable[t[i], frame] != -1) { p.Add(t[i]); } } intervals[frame] = new List <int[]>(); prev[frame] = new List <int>(); next[frame] = new List <int>(); lcss[frame] = new List <Tuple <int, int, int> >(); int last = -1; for (int i = 0; i < p.Count; ++i) { if (i == p.Count - 1 || story.SessionTable[p[i], frame] != story.SessionTable[p[i + 1], frame]) { intervals[frame].Add(p.GetRange(last + 1, i - last).ToArray <int>()); last = i; prev[frame].Add(-1); next[frame].Add(-1); lcss[frame].Add(new Tuple <int, int, int>(-1, -1, -1)); } } // calculate the connection with previous frame if (frame > 0) { Tuple <int, int, int>[,] lcs = new Tuple <int, int, int> [intervals[frame - 1].Count, intervals[frame].Count]; for (int i = 0; i < intervals[frame - 1].Count; ++i) { for (int j = 0; j < intervals[frame].Count; ++j) { lcs[i, j] = GetLcs(intervals[frame - 1][i], intervals[frame][j]); } } int[,] dp = new int[intervals[frame - 1].Count + 1, intervals[frame].Count + 1]; Tuple <int, int>[,] path = new Tuple <int, int> [intervals[frame - 1].Count + 1, intervals[frame].Count + 1]; for (int i = 0; i < intervals[frame - 1].Count; ++i) { for (int j = 0; j < intervals[frame].Count; ++j) { dp[i + 1, j + 1] = -1; if (dp[i + 1, j + 1] < dp[i, j] + lcs[i, j].Item3) { dp[i + 1, j + 1] = dp[i, j] + lcs[i, j].Item3; path[i + 1, j + 1] = new Tuple <int, int>(i, j); } if (dp[i + 1, j + 1] < dp[i + 1, j]) { dp[i + 1, j + 1] = dp[i + 1, j]; path[i + 1, j + 1] = new Tuple <int, int>(i + 1, j); } if (dp[i + 1, j + 1] < dp[i, j + 1]) { dp[i + 1, j + 1] = dp[i, j + 1]; path[i + 1, j + 1] = new Tuple <int, int>(i, j + 1); } } } { int i = intervals[frame - 1].Count - 1; int j = intervals[frame].Count - 1; while (i > -1 && j > -1) { if (path[i + 1, j + 1].Item1 == i && path[i + 1, j + 1].Item2 == j) { prev[frame][j] = i; next[frame - 1][i] = j; lcss[frame][j] = lcs[i, j]; } Tuple <int, int> pair = path[i + 1, j + 1]; i = pair.Item1 - 1; j = pair.Item2 - 1; } } } } int[] top = new int[frameCount]; List <List <Tuple <int, int> > > layers = new List <List <Tuple <int, int> > >(); while (true) { bool[] isAtTop = new bool[frameCount]; bool exist = false; for (int frame = 0; frame < frameCount; ++frame) { // now calculate a bool of isAtTop[frame] if (top[frame] >= intervals[frame].Count) // this frame is already empty { continue; } exist = true; bool flag = true; int current = prev[frame][top[frame]]; int currentFrame = frame - 1; while (current > -1) { if (top[currentFrame] != current) { flag = false; break; } current = prev[currentFrame][current]; --currentFrame; } current = next[frame][top[frame]]; currentFrame = frame + 1; while (current > -1) { if (top[currentFrame] != current) { flag = false; break; } current = next[currentFrame][current]; ++currentFrame; } isAtTop[frame] = flag; } if (!exist) { break; } layers.Add(new List <Tuple <int, int> >()); var layer = layers.Last <List <Tuple <int, int> > >(); for (int frame = 0; frame < frameCount; ++frame) { if (isAtTop[frame]) { layer.Add(new Tuple <int, int>(frame, top[frame])); ++top[frame]; } } } //Point[,] positions = new Point[permutation.FrameCount, permutation.CharacterCount]; //double[,] posY = new double[frameCount, characterCount]; int baseline = 0; int minY = int.MaxValue; int maxY = int.MinValue; for (int i = 0; i < layers.Count; ++i) { List <Tuple <int, int> > layer = layers[i]; int[] topY = new int[layer.Count]; int[] bottomY = new int[layer.Count]; int lastTopY = -100000; minY = int.MaxValue; maxY = int.MinValue; for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; if (prev[frame][k] == -1) { topY[j] = 0; lastTopY = 0; } else { topY[j] = lastTopY - lcss[frame][k].Item2 + lcss[frame][k].Item1; lastTopY = topY[j]; } if (minY > topY[j]) { minY = topY[j]; } } for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; topY[j] -= minY; bottomY[j] = topY[j] + intervals[frame][k].Length; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; posY[character, frame] = baseline + (topY[j] + ii) * (int)_app.Status.Config.Style.DefaultInnerGap; //positions[frame, character] = new Point(frame * styles.TimeScaleFactor, baseline + (topY[j] + ii) * styles.InnerDistance); if (maxY < posY[character, frame]) { maxY = (int)posY[character, frame]; } } } baseline = maxY + (int)_app.Status.Config.Style.OuterGap; } // new added, move down the hanging lines from bottom lay to top int[] topOfFrame = new int[story.TimeStamps.Length - 1]; for (int i = 0; i < topOfFrame.Length; ++i) { topOfFrame[i] = maxY; } for (int i = layers.Count - 1; i >= 0; --i) { List <Tuple <int, int> > layer = layers[i]; if (i != layers.Count - 1) // this is not the bottom layer { int minDepth = int.MaxValue; int BottomOfPiece = 0; int TopOfPieceGround = 0; List <Tuple <int, int> > stack = new List <Tuple <int, int> >(); for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; int max = int.MinValue; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; if (max < posY[character, frame]) { max = posY[character, frame]; } } if (prev[frame][k] == -1) { BottomOfPiece = max; TopOfPieceGround = topOfFrame[frame]; stack.Clear(); stack.Add(new Tuple <int, int>(frame, k)); } else { if (BottomOfPiece < max) { BottomOfPiece = max; } if (TopOfPieceGround > topOfFrame[frame]) { TopOfPieceGround = topOfFrame[frame]; } stack.Add(new Tuple <int, int>(frame, k)); } if (next[frame][k] == -1) { if (TopOfPieceGround - BottomOfPiece > (int)_app.Status.Config.Style.OuterGap * 2 - 1) { // a large gap detected int delta = TopOfPieceGround - BottomOfPiece - (int)_app.Status.Config.Style.OuterGap; int up = 0; int down = 0; foreach (Tuple <int, int> tuple in stack) { int f = tuple.Item1; int kk = tuple.Item2; for (int jj = 0; jj < intervals[f][kk].Length; ++jj) { int ch = intervals[f][kk][jj]; if (f < frameCount - 1) { if (story.SessionTable[ch, f + 1] != -1) { if (posY[ch, f] > posY[ch, f + 1]) { ++up; } else if (posY[ch, f] < posY[ch, f + 1]) { ++down; } } } if (f > 0) { if (story.SessionTable[ch, f - 1] != -1) { if (posY[ch, f] > posY[ch, f - 1]) { ++up; } else if (posY[ch, f] < posY[ch, f - 1]) { ++down; } } } } } if (down >= up) { foreach (Tuple <int, int> tuple in stack) { int f = tuple.Item1; int kk = tuple.Item2; for (int ii = 0; ii < intervals[f][kk].Length; ++ii) { int character = intervals[f][kk][ii]; posY[character, f] += delta; } } } } } } } for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; if (topOfFrame[frame] > posY[character, frame]) { topOfFrame[frame] = posY[character, frame]; } } } } // over } Debug.WriteLine("Crossing:{0}", Crossing.Count(story, posY)); return(posY.Clone <double>()); }
public PositionTable <double> Solve(Story story) { int frameCount = story.TimeStamps.Length - 1; int characterCount = story.Characters.Count; int[] orderedSequence = new int[characterCount]; for (int i = 0; i < characterCount; ++i) { orderedSequence[i] = i; } int[] permutation = Ultities.GetFeasiblePermutation(story, 0); PositionTable <int> permutationTable = new PositionTable <int>(characterCount, frameCount); for (int i = 0; i < characterCount; ++i) { for (int j = 0; j < frameCount; ++j) { permutationTable[i, j] = -1; } } for (int id = 0; id < characterCount; ++id) { if (story.SessionTable[id, 0] != -1) { permutationTable[id, 0] = permutation[id]; } } permutationTable = (new EfficientBarycenterCalculator()).Calculate(story); for (int xx = 0; xx < 10; ++xx) { // forward for (int frame = 1; frame < frameCount; ++frame) { Dictionary <int, List <int> > dict = new Dictionary <int, List <int> >(); for (int id = 0; id < characterCount; ++id) { if (story.SessionTable[id, frame] != -1) { if (!dict.ContainsKey(story.SessionTable[id, frame])) { dict.Add(story.SessionTable[id, frame], new List <int>()); } dict[story.SessionTable[id, frame]].Add(id); } } List <Tuple <int, double> > list = new List <Tuple <int, double> >(); foreach (KeyValuePair <int, List <int> > pair in dict) { int sum = 0; int count = 0; int sum_cur = 0; foreach (int x in pair.Value) { if (story.SessionTable[x, frame - 1] != -1) { sum += permutationTable[x, frame - 1]; ++count; } else { } sum_cur += permutationTable[x, frame]; } double average = (double)sum_cur / pair.Value.Count; if (count > 0) { average = (double)sum / count; } list.Add(new Tuple <int, double>(pair.Key, average)); } //list = Ultities.GetRandomList<Tuple<int, double>>(list); list.Sort((a, b) => a.Item2.CompareTo(b.Item2)); int baseline = 0; foreach (Tuple <int, double> tuple in list) { int group = tuple.Item1; List <int> items = dict[group]; //items = Ultities.GetRandomList<int>(items); items.Sort((a, b) => permutationTable[a, frame - 1].CompareTo(permutationTable[b, frame - 1])); foreach (int x in items) { permutationTable[x, frame] = baseline++; } } } Debug.WriteLine("Forward:{0}", Crossing.Count(story, permutationTable)); // backward for (int frame = frameCount - 2; frame >= 0; --frame) { Dictionary <int, List <int> > dict = new Dictionary <int, List <int> >(); for (int id = 0; id < characterCount; ++id) { if (story.SessionTable[id, frame] != -1) { if (!dict.ContainsKey(story.SessionTable[id, frame])) { dict.Add(story.SessionTable[id, frame], new List <int>()); } dict[story.SessionTable[id, frame]].Add(id); } } List <Tuple <int, double> > list = new List <Tuple <int, double> >(); foreach (KeyValuePair <int, List <int> > pair in dict) { int sum = 0; int count = 0; int sum_cur = 0; foreach (int x in pair.Value) { if (story.SessionTable[x, frame + 1] != -1) { sum += permutationTable[x, frame + 1]; ++count; } else { } sum_cur += permutationTable[x, frame]; } double average = (double)sum_cur / pair.Value.Count; if (count > 0) { average = (double)sum / count; } list.Add(new Tuple <int, double>(pair.Key, average)); } //list = Ultities.GetRandomList<Tuple<int, double>>(list); list.Sort((a, b) => a.Item2.CompareTo(b.Item2)); int baseline = 0; foreach (Tuple <int, double> tuple in list) { int group = tuple.Item1; List <int> items = dict[group]; //items = Ultities.GetRandomList<int>(items); items.Sort((a, b) => permutationTable[a, frame + 1].CompareTo(permutationTable[b, frame + 1])); foreach (int x in items) { permutationTable[x, frame] = baseline++; } } } Debug.WriteLine("Backward:{0}", Crossing.Count(story, permutationTable)); } for (int xx = 0; xx < 10; ++xx) { for (int frame = 0; frame < frameCount; ++frame) { Dictionary <int, List <int> > dict = new Dictionary <int, List <int> >(); for (int id = 0; id < characterCount; ++id) { if (story.SessionTable[id, frame] != -1) { if (!dict.ContainsKey(story.SessionTable[id, frame])) { dict.Add(story.SessionTable[id, frame], new List <int>()); } dict[story.SessionTable[id, frame]].Add(id); } } List <Tuple <int, double> > list = new List <Tuple <int, double> >(); foreach (KeyValuePair <int, List <int> > pair in dict) { int sum = 0; int count = 0; int sum_cur = 0; foreach (int x in pair.Value) { if (frame > 0 && story.SessionTable[x, frame - 1] != -1) { sum += permutationTable[x, frame - 1]; ++count; } if (frame < frameCount - 1 && story.SessionTable[x, frame + 1] != -1) { sum += permutationTable[x, frame + 1]; ++count; } sum_cur += permutationTable[x, frame]; } double average = (double)sum_cur / pair.Value.Count; if (count > 0) { average = (double)sum / count; } list.Add(new Tuple <int, double>(pair.Key, average)); } //list = Ultities.GetRandomList<Tuple<int, double>>(list); list.Sort((a, b) => a.Item2.CompareTo(b.Item2)); int baseline = 0; foreach (Tuple <int, double> tuple in list) { int group = tuple.Item1; List <int> items = dict[group]; //items = Ultities.GetRandomList<int>(items); //items.Sort((a, b) => permutationTable[a, frame].CompareTo(permutationTable[b, frame])); if (frame == 0) { items.Sort((a, b) => permutationTable[a, frame + 1].CompareTo(permutationTable[b, frame + 1])); } else { items.Sort((a, b) => permutationTable[a, frame - 1].CompareTo(permutationTable[b, frame - 1])); } foreach (int x in items) { permutationTable[x, frame] = baseline++; } } } // backward continue; for (int frame = frameCount - 1; frame >= 0; --frame) { Dictionary <int, List <int> > dict = new Dictionary <int, List <int> >(); for (int id = 0; id < characterCount; ++id) { if (story.SessionTable[id, frame] != -1) { if (!dict.ContainsKey(story.SessionTable[id, frame])) { dict.Add(story.SessionTable[id, frame], new List <int>()); } dict[story.SessionTable[id, frame]].Add(id); } } List <Tuple <int, double> > list = new List <Tuple <int, double> >(); foreach (KeyValuePair <int, List <int> > pair in dict) { int sum = 0; int count = 0; int sum_cur = 0; foreach (int x in pair.Value) { if (frame > 0 && story.SessionTable[x, frame - 1] != -1) { sum += permutationTable[x, frame - 1]; ++count; } if (frame < frameCount - 1 && story.SessionTable[x, frame + 1] != -1) { sum += permutationTable[x, frame + 1]; ++count; } sum_cur += permutationTable[x, frame]; } double average = (double)sum_cur / pair.Value.Count; if (count > 0) { average = (double)sum / count; } list.Add(new Tuple <int, double>(pair.Key, average)); } //list = Ultities.GetRandomList<Tuple<int, double>>(list); list.Sort((a, b) => a.Item2.CompareTo(b.Item2)); int baseline = 0; foreach (Tuple <int, double> tuple in list) { int group = tuple.Item1; List <int> items = dict[group]; //items = Ultities.GetRandomList<int>(items); //items.Sort((a, b) => permutationTable[a, frame].CompareTo(permutationTable[b, frame])); if (frame == 0) { items.Sort((a, b) => permutationTable[a, frame + 1].CompareTo(permutationTable[b, frame + 1])); } else { items.Sort((a, b) => permutationTable[a, frame - 1].CompareTo(permutationTable[b, frame - 1])); } foreach (int x in items) { permutationTable[x, frame] = baseline++; } } } } //PositionTable<int> permutationTable = (new EfficientBarycenterCalculator()).Calculate(story); permutationTable = (new EfficientBarycenterCalculator()).Calculate(story); //permutationTable = (new CrossingMinimizedCalculator()).Calculate(story); for (int frame = 0; frame < frameCount; ++frame) { int max = -1; for (int id = 0; id < characterCount; ++id) { if (permutationTable[id, frame] > max) { max = permutationTable[id, frame]; } } for (int id = 0; id < characterCount; ++id) { if (permutationTable[id, frame] == -1) { permutationTable[id, frame] = ++max; } } } Debug.WriteLine("Crossing:{0}", Crossing.Count(story, permutationTable)); //PositionTable<int> ans = permutationTable.Clone<int>(); //for (int frame = 0; frame < frameCount; ++frame) //{ // for (int i = 0; i < story.Characters.Count; ++i) // { // ans[i, frame] *= 5; // } //} //return ans; { // calculate positions PositionTable <int> posY = new PositionTable <int>(characterCount, frameCount); List <int[]>[] intervals = new List <int[]> [frameCount]; List <int>[] prev = new List <int> [frameCount]; List <int>[] next = new List <int> [frameCount]; List <Tuple <int, int, int> >[] lcss = new List <Tuple <int, int, int> > [frameCount]; for (int frame = 0; frame < frameCount; ++frame) { // find intervals at this frame int[] t = new int[characterCount]; for (int i = 0; i < characterCount; ++i) { t[permutationTable[i, frame]] = i; } List <int> p = new List <int>(); for (int i = 0; i < t.Length; ++i) { if (story.SessionTable[t[i], frame] != -1) { p.Add(t[i]); } } intervals[frame] = new List <int[]>(); prev[frame] = new List <int>(); next[frame] = new List <int>(); lcss[frame] = new List <Tuple <int, int, int> >(); int last = -1; for (int i = 0; i < p.Count; ++i) { if (i == p.Count - 1 || story.SessionTable[p[i], frame] != story.SessionTable[p[i + 1], frame]) { intervals[frame].Add(p.GetRange(last + 1, i - last).ToArray <int>()); last = i; prev[frame].Add(-1); next[frame].Add(-1); lcss[frame].Add(new Tuple <int, int, int>(-1, -1, -1)); } } // calculate the connection with previous frame if (frame > 0) { Tuple <int, int, int>[,] lcs = new Tuple <int, int, int> [intervals[frame - 1].Count, intervals[frame].Count]; for (int i = 0; i < intervals[frame - 1].Count; ++i) { for (int j = 0; j < intervals[frame].Count; ++j) { lcs[i, j] = GetLcs(intervals[frame - 1][i], intervals[frame][j]); } } int[,] dp = new int[intervals[frame - 1].Count + 1, intervals[frame].Count + 1]; Tuple <int, int>[,] path = new Tuple <int, int> [intervals[frame - 1].Count + 1, intervals[frame].Count + 1]; for (int i = 0; i < intervals[frame - 1].Count; ++i) { for (int j = 0; j < intervals[frame].Count; ++j) { dp[i + 1, j + 1] = -1; if (dp[i + 1, j + 1] < dp[i, j] + lcs[i, j].Item3) { dp[i + 1, j + 1] = dp[i, j] + lcs[i, j].Item3; path[i + 1, j + 1] = new Tuple <int, int>(i, j); } if (dp[i + 1, j + 1] < dp[i + 1, j]) { dp[i + 1, j + 1] = dp[i + 1, j]; path[i + 1, j + 1] = new Tuple <int, int>(i + 1, j); } if (dp[i + 1, j + 1] < dp[i, j + 1]) { dp[i + 1, j + 1] = dp[i, j + 1]; path[i + 1, j + 1] = new Tuple <int, int>(i, j + 1); } } } { int i = intervals[frame - 1].Count - 1; int j = intervals[frame].Count - 1; while (i > -1 && j > -1) { if (path[i + 1, j + 1].Item1 == i && path[i + 1, j + 1].Item2 == j) { prev[frame][j] = i; next[frame - 1][i] = j; lcss[frame][j] = lcs[i, j]; } Tuple <int, int> pair = path[i + 1, j + 1]; i = pair.Item1 - 1; j = pair.Item2 - 1; } } } } int[] top = new int[frameCount]; List <List <Tuple <int, int> > > layers = new List <List <Tuple <int, int> > >(); while (true) { bool[] isAtTop = new bool[frameCount]; bool exist = false; for (int frame = 0; frame < frameCount; ++frame) { // now calculate a bool of isAtTop[frame] if (top[frame] >= intervals[frame].Count) // this frame is already empty { continue; } exist = true; bool flag = true; int current = prev[frame][top[frame]]; int currentFrame = frame - 1; while (current > -1) { if (top[currentFrame] != current) { flag = false; break; } current = prev[currentFrame][current]; --currentFrame; } current = next[frame][top[frame]]; currentFrame = frame + 1; while (current > -1) { if (top[currentFrame] != current) { flag = false; break; } current = next[currentFrame][current]; ++currentFrame; } isAtTop[frame] = flag; } if (!exist) { break; } layers.Add(new List <Tuple <int, int> >()); var layer = layers.Last <List <Tuple <int, int> > >(); for (int frame = 0; frame < frameCount; ++frame) { if (isAtTop[frame]) { layer.Add(new Tuple <int, int>(frame, top[frame])); ++top[frame]; } } } //Point[,] positions = new Point[permutation.FrameCount, permutation.CharacterCount]; //double[,] posY = new double[frameCount, characterCount]; int yBaseline = 0; int minY = int.MaxValue; int maxY = int.MinValue; for (int i = 0; i < layers.Count; ++i) { List <Tuple <int, int> > layer = layers[i]; int[] topY = new int[layer.Count]; int[] bottomY = new int[layer.Count]; int lastTopY = -100000; minY = int.MaxValue; maxY = int.MinValue; for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; if (prev[frame][k] == -1) { topY[j] = 0; lastTopY = 0; } else { topY[j] = lastTopY - lcss[frame][k].Item2 + lcss[frame][k].Item1; lastTopY = topY[j]; } if (minY > topY[j]) { minY = topY[j]; } } for (int j = 0; j < layer.Count; ++j) { int frame = layer[j].Item1; int k = layer[j].Item2; topY[j] -= minY; bottomY[j] = topY[j] + intervals[frame][k].Length; for (int ii = 0; ii < intervals[frame][k].Length; ++ii) { int character = intervals[frame][k][ii]; posY[character, frame] = yBaseline + (topY[j] + ii) * (int)_app.Status.Config.Style.DefaultInnerGap; //positions[frame, character] = new Point(frame * styles.TimeScaleFactor, baseline + (topY[j] + ii) * styles.InnerDistance); if (maxY < posY[character, frame]) { maxY = (int)posY[character, frame]; } } } yBaseline = maxY + (int)_app.Status.Config.Style.OuterGap; } return(posY.Clone <double>()); PositionTable <double> position = posY.Clone <double>(); for (int frame = 0; frame < frameCount; ++frame) { for (int i = 0; i < story.Characters.Count; ++i) { position[i, frame] /= 5; } } PositionOptimizer3 optimizer2 = new PositionOptimizer3(); PositionOptimizer2 optimizer = new PositionOptimizer2(); position = optimizer.Optimize(story, position, 1.0, 0.05, 0.0, 0.0); PositionOptimizer1 optimizer1 = new PositionOptimizer1(); int x = 0; while (x-- > 0) { position = optimizer1.Optimize(story, position); position = optimizer.Optimize(story, position, 1.0, 0.03, 0.0, 0.0); } double min = 0; for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1 && min > position[id, frame]) { min = position[id, frame]; } } } for (int id = 0; id < story.Characters.Count; ++id) { for (int frame = 0; frame < story.TimeStamps.Length - 1; ++frame) { if (story.SessionTable[id, frame] != -1) { position[id, frame] -= min; position[id, frame] *= 5; } } } return(position); } }