private double CalculateDCDensity(int index, CatcherInfo catcher, int[] DCtimes, double basevelocity, double difficulty) { int DCindex = Array.BinarySearch(DCtimes, times[index]); if (DCindex > 0) { int DCcount = 0; double DCsum = 0; for (int j = DCindex; j > 0 && DCcount <= 10 && DCtimes[DCindex] - DCtimes[j] < 10000; j--) { DCcount++; DCsum += DCtimes[j] - DCtimes[j - 1]; } //Want inverse of average, so flip sum and count double DCmultiplier = Math.Pow(DCcount / DCsum * 500, 1) * catcher.GetCSMultiplier(); difficulty += basevelocity * DCmultiplier; //Previous jump was a hyper checking if (index > 2 && times[index - 1] != times[index - 2]) { double prevspeed = catcher.PercentHyper(Math.Abs(positions[index - 1] - positions[index - 2]), times[index - 1] - times[index - 2]); //If the previous jump was a hyper, scale difficulty to do DC by how fast the hyper was going if (prevspeed > 1) { difficulty += Math.Pow(prevspeed * 0.70, 2.3); } } double DChypermultiplier = Math.Pow(DCcount / DCsum * 50, 2); difficulty = CalculateHyperChanges(index, DCtimes, catcher, DChypermultiplier, difficulty); } return(difficulty); }
//Each hitobject marked as a "DC" means that it requires a directional change to catch public int[] GetDirectionalChangeTimes() { double circlesize = Double.Parse(map.GetTag("Difficulty", "CircleSize"), CultureInfo.InvariantCulture); CatcherInfo catcher = new CatcherInfo(circlesize); List <int> DCtimes = new List <int>(); Direction prevnotedir = catcher.CurDirection; for (int i = 1; i < hitpositions.Length; i++) { if (hitpositions[i] == hitpositions[i - 1]) { continue; } Direction notedirection; if (hitpositions[i] - hitpositions[i - 1] > 0) { notedirection = Direction.Right; } else { notedirection = Direction.Left; } bool isprevhyper; if (i > 1 && hittimes[i - 1] != hittimes[i - 2]) { isprevhyper = catcher.PercentHyper(Math.Abs(hitpositions[i - 1] - hitpositions[i - 2]), hittimes[i - 1] - hittimes[i - 2]) > 1; } else { isprevhyper = false; } int distance = Math.Abs(hitpositions[i] - hitpositions[i - 1]); double checkedsize = catcher.CatcherSize; if (isprevhyper) { checkedsize /= 2; } if (notedirection != catcher.CurDirection && (distance > checkedsize || notedirection == prevnotedir)) { catcher.CurDirection = notedirection; DCtimes.Add(hittimes[i]); } prevnotedir = catcher.CurDirection; } return(DCtimes.ToArray()); }
public int[] GetStopGoTimes() { double circlesize = Double.Parse(map.GetTag("Difficulty", "CircleSize"), CultureInfo.InvariantCulture); CatcherInfo catcher = new CatcherInfo(circlesize); List<int> SGtimes = new List<int>(); for(int i = 1; i < hitpositions.Length; i++) { if(hittimes[i] == hittimes[i-1] || Math.Abs(hitpositions[i] - hitpositions[i-1]) < 110) continue; double velocity = catcher.PercentHyper(Math.Abs(hitpositions[i] - hitpositions[i-1]), hittimes[i] - hittimes[i-1]); //Skip if not a hyper if(velocity <= 1) continue; //Skip if last two notes can't be caught together if(i < 2 || hitpositions[i-1] - hitpositions[i-2] > catcher.CatcherSize) continue; //Represents the last note that required no movement before the hyper jump int lastnonmoveindex = i-2; int leftmost = hitpositions[i-1] > hitpositions[i-2] ? hitpositions[i-2] : hitpositions[i-1]; int rightmost = hitpositions[i-1] > hitpositions[i-2] ? hitpositions[i-1] : hitpositions[i-2]; int templeft = leftmost; int tempright = rightmost; while(lastnonmoveindex > 0) { //Update the "bounds" of the pattern if(hitpositions[lastnonmoveindex-1] < leftmost) templeft = hitpositions[lastnonmoveindex-1]; else if(hitpositions[lastnonmoveindex-1] > rightmost) tempright = hitpositions[lastnonmoveindex-1]; //Actual "check" of the loop if(tempright - templeft > (catcher.CatcherSize)) break; leftmost = templeft; rightmost = tempright; lastnonmoveindex--; } int nonmovetime = hittimes[i] - hittimes[lastnonmoveindex]; if((rightmost - leftmost) / (double)nonmovetime < 0.5) SGtimes.Add(hittimes[i]); } return SGtimes.ToArray(); }
List <List <int> > GenerateMovingObjects(List <object> objs) { List <List <int> > res = new List <List <int> >(); foreach (object o in objs) { try { int id; int type; int[] param; if (o is ShooterInfo) { ShooterInfo si = (ShooterInfo)o; id = si.ID; type = 0xF4; param = si.Params(); } else if (o is PistonInfo) { PistonInfo pi = (PistonInfo)o; id = pi.ID; type = 0xF5; param = pi.Params(); } else if (o is RollerInfo) { RollerInfo ri = (RollerInfo)o; id = ri.ID; type = 0xF7; param = ri.Params(); } else // CatcherInfo { CatcherInfo ci = (CatcherInfo)o; id = ci.ID; type = 0xF6; param = ci.Params(); } List <int> elt = new List <int>(); elt.Add(0xF1); elt.AddRange(GenerateMapInfoData(new int[] { id })); elt.Add(type); elt.AddRange(GenerateMapInfoData(param)); res.Add(elt); } catch { } } return(res); }
//Gets a list of every hitpoint and its associated difficulty public HitPoint[] GetNoteDifficulty() { double circlesize = Double.Parse(map.GetTag("Difficulty", "CircleSize"), CultureInfo.InvariantCulture); CatcherInfo catcher = new CatcherInfo(circlesize); PatternParser patterndetector = new PatternParser(map, positions, times); int[] DCtimes = patterndetector.GetDirectionalChangeTimes(); int[] SGtimes = patterndetector.GetStopGoTimes(); List <HitPoint> notes = new List <HitPoint>(); for (int i = 1; i < positions.Length; i++) { //Cast to make division operation a double //double velocity = Math.Abs(positions[i] - positions[i-1]) / (double)(times[i] - times[i-1]); //Scale velocity to be a percent of a pixel-jump - a pixel jump is equal to 1 double velocity = catcher.PercentHyper(Math.Abs(positions[i] - positions[i - 1]), times[i] - times[i - 1]); if (velocity > 1) { velocity = 0.2; //velocity = 1.0 / Math.Pow((times[i] - times[i-1]), 0.3); } else { //Scale normal jumps velocity = Math.Pow(velocity, 2); } double difficulty = velocity; difficulty = this.CalculateNonmovementDifficulty(i, catcher, difficulty); difficulty = this.CalculateDCDensity(i, catcher, DCtimes, velocity, difficulty); //difficulty = this.CalculateHyperChanges(i, DCtimes, catcher, difficulty); //difficulty = this.CalculateSGDensity(i, SGtimes, velocity, difficulty); notes.Add(new HitPoint(positions[i], times[i], difficulty, i)); } return(notes.ToArray()); }
//Each hitobject marked as a "DC" means that it requires a directional change to catch public int[] GetDirectionalChangeTimes() { double circlesize = Double.Parse(map.GetTag("Difficulty", "CircleSize"), CultureInfo.InvariantCulture); CatcherInfo catcher = new CatcherInfo(circlesize); List<int> DCtimes = new List<int>(); Direction prevnotedir = catcher.CurDirection; for(int i = 1; i < hitpositions.Length; i++) { if(hitpositions[i] == hitpositions[i-1]) continue; Direction notedirection; if(hitpositions[i] - hitpositions[i-1] > 0) notedirection = Direction.Right; else notedirection = Direction.Left; bool isprevhyper; if(i > 1 && hittimes[i-1] != hittimes[i-2]) isprevhyper = catcher.PercentHyper(Math.Abs(hitpositions[i-1] - hitpositions[i-2]), hittimes[i-1] - hittimes[i-2]) > 1; else isprevhyper = false; int distance = Math.Abs(hitpositions[i]-hitpositions[i-1]); double checkedsize = catcher.CatcherSize; if(isprevhyper) checkedsize /= 2; if(notedirection != catcher.CurDirection && (distance > checkedsize || notedirection == prevnotedir)) { catcher.CurDirection = notedirection; DCtimes.Add(hittimes[i]); } prevnotedir = catcher.CurDirection; } return DCtimes.ToArray(); }
//Scale velocity based on whether the previous note was a hyper dash or not, compared to this jump private double CalculateHyperChanges(int index, int[] DCtimes, CatcherInfo catcher, double DCmultiplier, double difficulty) { if (index > 1) { double prevvel = catcher.PercentHyper(Math.Abs(positions[index - 1] - positions[index - 2]), (times[index - 1] - times[index - 2])); double thisvel = catcher.PercentHyper(Math.Abs(positions[index] - positions[index - 1]), (times[index] - times[index - 1])); if (prevvel > 1 && thisvel <= 1 && Math.Abs(positions[index] - positions[index - 1]) > catcher.CatcherSize / 2) { //Already know that this note requires a DC difficulty += (DCmultiplier * 1 * Math.Pow(thisvel, 2)); //next note requires a DC //Does not "double dip difficulty", as this note becomes harder to catch if the next note requires a DC //(since you have to time the DC correctly) if (index + 1 < positions.Length && Array.BinarySearch(DCtimes, times[index + 1]) > 0) { difficulty += (DCmultiplier * 1 * Math.Pow(thisvel, 2)); } } } return(difficulty); }
private double CalculateNonmovementDifficulty(int index, CatcherInfo catcher, double difficulty) { //Check if the last three notes can be caught without moving //Prevents unnecessary checking if (index > 2 && Math.Max(Math.Max(positions[index], positions[index - 1]), positions[index - 2]) - Math.Min(Math.Min(positions[index], positions[index - 1]), positions[index - 2]) < catcher.CatcherSize) { //the distance the catcher moves, scaled as a percentage of how close the jump is to requiring movement double totalpercentdistance = 0; //index locating what note is the last note not needing movement to catch int nonmovementindex; //Makes sure that the notes aren't all in a straight line int leftmost = Math.Max(positions[index], positions[index - 1]); int rightmost = Math.Min(positions[index], positions[index - 1]); //used to make sure we only get at most 10 notes int nonmovecount = 0; int DCcount = 0; List <int> nonmoveDCtimes = new List <int>(); Direction curdir; if (positions[index] - positions[index - 1] > 0) { curdir = Direction.Right; } else if (positions[index] - positions[index - 1] < 0) { curdir = Direction.Left; } else { curdir = Direction.Stop; } Direction prevdir = curdir; //while it's still a nonmovement jump for (nonmovementindex = index; nonmovementindex > 0 && nonmovecount < 10; nonmovementindex--) { if (positions[nonmovementindex] > leftmost) { leftmost = positions[nonmovementindex]; } else if (positions[nonmovementindex] < rightmost) { rightmost = positions[nonmovementindex]; } if (positions[nonmovementindex] - positions[nonmovementindex - 1] > 0) { curdir = Direction.Right; } else if (positions[nonmovementindex] - positions[nonmovementindex - 1] < 0) { curdir = Direction.Left; } if (leftmost - rightmost > catcher.CatcherSize) { break; } if (positions[nonmovementindex] - positions[nonmovementindex - 1] > catcher.CatcherSize) { break; } if (curdir != prevdir) { DCcount++; nonmoveDCtimes.Add(times[nonmovecount]); } prevdir = curdir; totalpercentdistance += Math.Abs(positions[nonmovementindex] - positions[nonmovementindex - 1]) / (double)catcher.CatcherSize; nonmovecount++; } //Get the sum of the time between DC's in the nonmovement section double nonmoveDCsum = 0; for (int i = 1; i < nonmoveDCtimes.Count; i++) { nonmoveDCsum += nonmoveDCtimes[i] - nonmoveDCtimes[i - 1]; } double pendingdiff; if (nonmoveDCsum == 0) { pendingdiff = 0; } else { pendingdiff = 110 * Math.Pow(DCcount / nonmoveDCsum, 0.72) * (Math.Pow(totalpercentdistance, 5) / (Math.Pow(10, 5) / 10)); } difficulty = Math.Max(pendingdiff, difficulty); } return(difficulty); }
//Scale velocity based on whether the previous note was a hyper dash or not, compared to this jump private double CalculateHyperChanges(int index, int[] DCtimes, CatcherInfo catcher, double DCmultiplier, double difficulty) { if(index > 1) { double prevvel = catcher.PercentHyper(Math.Abs(positions[index-1] - positions[index-2]), (times[index-1] - times[index-2])); double thisvel = catcher.PercentHyper(Math.Abs(positions[index] - positions[index-1]), (times[index] - times[index-1])); if(prevvel > 1 && thisvel <= 1 && Math.Abs(positions[index] - positions[index-1]) > catcher.CatcherSize / 2) { //Already know that this note requires a DC difficulty += (DCmultiplier * 1 * Math.Pow(thisvel, 2)); //next note requires a DC //Does not "double dip difficulty", as this note becomes harder to catch if the next note requires a DC //(since you have to time the DC correctly) if(index + 1 < positions.Length && Array.BinarySearch(DCtimes, times[index+1]) > 0) difficulty += (DCmultiplier * 1 * Math.Pow(thisvel, 2)); } } return difficulty; }
private double CalculateDCDensity(int index, CatcherInfo catcher, int[] DCtimes, double basevelocity, double difficulty) { int DCindex = Array.BinarySearch(DCtimes, times[index]); if(DCindex > 0) { int DCcount = 0; double DCsum = 0; for(int j = DCindex; j > 0 && DCcount <= 10 && DCtimes[DCindex] - DCtimes[j] < 10000; j--) { DCcount++; DCsum += DCtimes[j] - DCtimes[j-1]; } //Want inverse of average, so flip sum and count double DCmultiplier = Math.Pow(DCcount / DCsum * 500, 1) * catcher.GetCSMultiplier(); difficulty += basevelocity * DCmultiplier; //Previous jump was a hyper checking if(index > 2 && times[index-1] != times[index-2]) { double prevspeed = catcher.PercentHyper(Math.Abs(positions[index-1] - positions[index-2]), times[index-1] - times[index-2]); //If the previous jump was a hyper, scale difficulty to do DC by how fast the hyper was going if(prevspeed > 1) difficulty += Math.Pow(prevspeed * 0.70, 2.3); } double DChypermultiplier = Math.Pow(DCcount / DCsum * 50, 2); difficulty = CalculateHyperChanges(index, DCtimes, catcher, DChypermultiplier, difficulty); } return difficulty; }
private double CalculateNonmovementDifficulty(int index, CatcherInfo catcher, double difficulty) { //Check if the last three notes can be caught without moving //Prevents unnecessary checking if(index > 2 && Math.Max(Math.Max(positions[index], positions[index-1]), positions[index-2]) - Math.Min(Math.Min(positions[index], positions[index-1]), positions[index-2]) < catcher.CatcherSize) { //the distance the catcher moves, scaled as a percentage of how close the jump is to requiring movement double totalpercentdistance = 0; //index locating what note is the last note not needing movement to catch int nonmovementindex; //Makes sure that the notes aren't all in a straight line int leftmost = Math.Max(positions[index], positions[index-1]); int rightmost = Math.Min(positions[index], positions[index-1]); //used to make sure we only get at most 10 notes int nonmovecount = 0; int DCcount = 0; List<int> nonmoveDCtimes = new List<int>(); Direction curdir; if(positions[index] - positions[index-1] > 0) curdir = Direction.Right; else if(positions[index] - positions[index-1] < 0) curdir = Direction.Left; else curdir = Direction.Stop; Direction prevdir = curdir; //while it's still a nonmovement jump for(nonmovementindex = index; nonmovementindex > 0 && nonmovecount < 10; nonmovementindex--) { if(positions[nonmovementindex] > leftmost) leftmost = positions[nonmovementindex]; else if(positions[nonmovementindex] < rightmost) rightmost = positions[nonmovementindex]; if(positions[nonmovementindex] - positions[nonmovementindex-1] > 0) curdir = Direction.Right; else if(positions[nonmovementindex] - positions[nonmovementindex-1] < 0) curdir = Direction.Left; if(leftmost - rightmost > catcher.CatcherSize) break; if(positions[nonmovementindex] - positions[nonmovementindex-1] > catcher.CatcherSize) break; if(curdir != prevdir) { DCcount++; nonmoveDCtimes.Add(times[nonmovecount]); } prevdir = curdir; totalpercentdistance += Math.Abs(positions[nonmovementindex] - positions[nonmovementindex-1]) / (double)catcher.CatcherSize; nonmovecount++; } //Get the sum of the time between DC's in the nonmovement section double nonmoveDCsum = 0; for(int i = 1; i < nonmoveDCtimes.Count; i++) nonmoveDCsum += nonmoveDCtimes[i] - nonmoveDCtimes[i-1]; double pendingdiff; if(nonmoveDCsum == 0) pendingdiff = 0; else pendingdiff = 110 * Math.Pow(DCcount / nonmoveDCsum, 0.72) * (Math.Pow(totalpercentdistance, 5) / (Math.Pow(10, 5) / 10)); difficulty = Math.Max(pendingdiff, difficulty); } return difficulty; }
//Gets a list of every hitpoint and its associated difficulty public HitPoint[] GetNoteDifficulty() { double circlesize = Double.Parse(map.GetTag("Difficulty", "CircleSize"), CultureInfo.InvariantCulture); CatcherInfo catcher = new CatcherInfo(circlesize); PatternParser patterndetector = new PatternParser(map, positions, times); int[] DCtimes = patterndetector.GetDirectionalChangeTimes(); int[] SGtimes = patterndetector.GetStopGoTimes(); List<HitPoint> notes = new List<HitPoint>(); for(int i = 1; i < positions.Length; i++) { //Cast to make division operation a double //double velocity = Math.Abs(positions[i] - positions[i-1]) / (double)(times[i] - times[i-1]); //Scale velocity to be a percent of a pixel-jump - a pixel jump is equal to 1 double velocity = catcher.PercentHyper(Math.Abs(positions[i] - positions[i-1]), times[i] - times[i-1]); if(velocity > 1) { velocity = 0.2; //velocity = 1.0 / Math.Pow((times[i] - times[i-1]), 0.3); } else { //Scale normal jumps velocity = Math.Pow(velocity, 2); } double difficulty = velocity; difficulty = this.CalculateNonmovementDifficulty(i, catcher, difficulty); difficulty = this.CalculateDCDensity(i, catcher, DCtimes, velocity, difficulty); //difficulty = this.CalculateHyperChanges(i, DCtimes, catcher, difficulty); //difficulty = this.CalculateSGDensity(i, SGtimes, velocity, difficulty); notes.Add(new HitPoint(positions[i], times[i], difficulty, i)); } return notes.ToArray(); }
public int[] GetStopGoTimes() { double circlesize = Double.Parse(map.GetTag("Difficulty", "CircleSize"), CultureInfo.InvariantCulture); CatcherInfo catcher = new CatcherInfo(circlesize); List <int> SGtimes = new List <int>(); for (int i = 1; i < hitpositions.Length; i++) { if (hittimes[i] == hittimes[i - 1] || Math.Abs(hitpositions[i] - hitpositions[i - 1]) < 110) { continue; } double velocity = catcher.PercentHyper(Math.Abs(hitpositions[i] - hitpositions[i - 1]), hittimes[i] - hittimes[i - 1]); //Skip if not a hyper if (velocity <= 1) { continue; } //Skip if last two notes can't be caught together if (i < 2 || hitpositions[i - 1] - hitpositions[i - 2] > catcher.CatcherSize) { continue; } //Represents the last note that required no movement before the hyper jump int lastnonmoveindex = i - 2; int leftmost = hitpositions[i - 1] > hitpositions[i - 2] ? hitpositions[i - 2] : hitpositions[i - 1]; int rightmost = hitpositions[i - 1] > hitpositions[i - 2] ? hitpositions[i - 1] : hitpositions[i - 2]; int templeft = leftmost; int tempright = rightmost; while (lastnonmoveindex > 0) { //Update the "bounds" of the pattern if (hitpositions[lastnonmoveindex - 1] < leftmost) { templeft = hitpositions[lastnonmoveindex - 1]; } else if (hitpositions[lastnonmoveindex - 1] > rightmost) { tempright = hitpositions[lastnonmoveindex - 1]; } //Actual "check" of the loop if (tempright - templeft > (catcher.CatcherSize)) { break; } leftmost = templeft; rightmost = tempright; lastnonmoveindex--; } int nonmovetime = hittimes[i] - hittimes[lastnonmoveindex]; if ((rightmost - leftmost) / (double)nonmovetime < 0.5) { SGtimes.Add(hittimes[i]); } } return(SGtimes.ToArray()); }