Skip to content

Commit

Permalink
Merge pull request #1 from stanriders/main
Browse files Browse the repository at this point in the history
Release 1.0.0
  • Loading branch information
stanriders authored Sep 16, 2022
2 parents 94cdb70 + 69259fa commit e1aa3ab
Show file tree
Hide file tree
Showing 37 changed files with 1,241 additions and 2 deletions.
194 changes: 194 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# EditorConfig is awesome: http://editorconfig.org
root = true

[*.cs]
end_of_line = crlf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

#Roslyn naming styles

#PascalCase for public and protected members
dotnet_naming_style.pascalcase.capitalization = pascal_case
dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event
dotnet_naming_rule.public_members_pascalcase.severity = error
dotnet_naming_rule.public_members_pascalcase.symbols = public_members
dotnet_naming_rule.public_members_pascalcase.style = pascalcase

#camelCase for private members
dotnet_naming_style.camelcase.capitalization = camel_case

dotnet_naming_symbols.private_members.applicable_accessibilities = private
dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event
dotnet_naming_rule.private_members_camelcase.severity = warning
dotnet_naming_rule.private_members_camelcase.symbols = private_members
dotnet_naming_rule.private_members_camelcase.style = camelcase

dotnet_naming_symbols.local_function.applicable_kinds = local_function
dotnet_naming_rule.local_function_camelcase.severity = warning
dotnet_naming_rule.local_function_camelcase.symbols = local_function
dotnet_naming_rule.local_function_camelcase.style = camelcase

#all_lower for private and local constants/static readonlys
dotnet_naming_style.all_lower.capitalization = all_lower
dotnet_naming_style.all_lower.word_separator = _

dotnet_naming_symbols.private_constants.applicable_accessibilities = private
dotnet_naming_symbols.private_constants.required_modifiers = const
dotnet_naming_symbols.private_constants.applicable_kinds = field
dotnet_naming_rule.private_const_all_lower.severity = warning
dotnet_naming_rule.private_const_all_lower.symbols = private_constants
dotnet_naming_rule.private_const_all_lower.style = all_lower

dotnet_naming_symbols.private_static_readonly.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly.required_modifiers = static,readonly
dotnet_naming_symbols.private_static_readonly.applicable_kinds = field
dotnet_naming_rule.private_static_readonly_all_lower.severity = warning
dotnet_naming_rule.private_static_readonly_all_lower.symbols = private_static_readonly
dotnet_naming_rule.private_static_readonly_all_lower.style = all_lower

dotnet_naming_symbols.local_constants.applicable_kinds = local
dotnet_naming_symbols.local_constants.required_modifiers = const
dotnet_naming_rule.local_const_all_lower.severity = warning
dotnet_naming_rule.local_const_all_lower.symbols = local_constants
dotnet_naming_rule.local_const_all_lower.style = all_lower

#ALL_UPPER for non private constants/static readonlys
dotnet_naming_style.all_upper.capitalization = all_upper
dotnet_naming_style.all_upper.word_separator = _

dotnet_naming_symbols.public_constants.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_constants.required_modifiers = const
dotnet_naming_symbols.public_constants.applicable_kinds = field
dotnet_naming_rule.public_const_all_upper.severity = warning
dotnet_naming_rule.public_const_all_upper.symbols = public_constants
dotnet_naming_rule.public_const_all_upper.style = all_upper

dotnet_naming_symbols.public_static_readonly.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_static_readonly.required_modifiers = static,readonly
dotnet_naming_symbols.public_static_readonly.applicable_kinds = field
dotnet_naming_rule.public_static_readonly_all_upper.severity = warning
dotnet_naming_rule.public_static_readonly_all_upper.symbols = public_static_readonly
dotnet_naming_rule.public_static_readonly_all_upper.style = all_upper

#Roslyn formating options

#Formatting - indentation options
csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = false
csharp_indent_labels = one_less_than_current
csharp_indent_switch_labels = true

#Formatting - new line options
csharp_new_line_before_catch = true
csharp_new_line_before_else = true
csharp_new_line_before_finally = true
csharp_new_line_before_open_brace = all
#csharp_new_line_before_members_in_anonymous_types = true
#csharp_new_line_before_members_in_object_initializers = true # Currently no effect in VS/dotnet format (16.4), and makes Rider confusing
csharp_new_line_between_query_expression_clauses = true

#Formatting - organize using options
dotnet_sort_system_directives_first = true

#Formatting - spacing options
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false

#Formatting - wrapping options
csharp_preserve_single_line_blocks = true
csharp_preserve_single_line_statements = true

#Roslyn language styles

#Style - this. qualification
dotnet_style_qualification_for_field = false:warning
dotnet_style_qualification_for_property = false:warning
dotnet_style_qualification_for_method = false:warning
dotnet_style_qualification_for_event = false:warning

#Style - type names
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
csharp_style_var_when_type_is_apparent = true:none
csharp_style_var_for_built_in_types = true:none
csharp_style_var_elsewhere = true:silent

#Style - modifiers
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
csharp_preferred_modifier_order = public,private,protected,internal,new,abstract,virtual,sealed,override,static,readonly,extern,unsafe,volatile,async:warning

#Style - parentheses
# Skipped because roslyn cannot separate +-*/ with << >>

#Style - expression bodies
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_constructors = false:none
csharp_style_expression_bodied_indexers = true:warning
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = true:warning
csharp_style_expression_bodied_properties = true:warning
csharp_style_expression_bodied_local_functions = true:silent

#Style - expression preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
dotnet_style_prefer_compound_assignment = true:warning

#Style - null/type checks
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
csharp_style_throw_expression = true:silent
csharp_style_conditional_delegate_call = true:warning

#Style - unused
dotnet_style_readonly_field = true:silent
dotnet_code_quality_unused_parameters = non_public:silent
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
csharp_style_unused_value_assignment_preference = discard_variable:warning

#Style - variable declaration
csharp_style_inlined_variable_declaration = true:warning
csharp_style_deconstructed_variable_declaration = true:warning

#Style - other C# 7.x features
dotnet_style_prefer_inferred_tuple_names = true:warning
csharp_prefer_simple_default_expression = true:warning
csharp_style_pattern_local_over_anonymous_function = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent

#Style - C# 8 features
csharp_prefer_static_local_function = true:warning
csharp_prefer_simple_using_statement = true:silent
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
csharp_style_prefer_switch_expression = false:none

#Supressing roslyn built-in analyzers
# Suppress: EC112

#Private method is unused
dotnet_diagnostic.IDE0051.severity = silent
#Private member is unused
dotnet_diagnostic.IDE0052.severity = silent

#Rules for disposable
dotnet_diagnostic.IDE0067.severity = none
dotnet_diagnostic.IDE0068.severity = none
dotnet_diagnostic.IDE0069.severity = none
48 changes: 48 additions & 0 deletions Pettanko.Tests/CalculatorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Pettanko.Difficulty;
using Pettanko.Performance;
using Xunit;

namespace Pettanko.Tests
{
public class CalculatorTests
{
[Fact]
public void TestOsuCalculator()
{
var result = Pettanko.Calculate(
new OsuDifficultyAttributes
{
AimDifficulty = 2.9864489908605893,
SpeedDifficulty = 3.1111283473891254,
FlashlightDifficulty = 3.54341969421949,
SliderFactor = 0.99796469139376365,
ApproachRate = 9.50,
OverallDifficulty = 9.00,
MaxCombo = 3220,
HitCircleCount = 1534,
SliderCount = 587,
SpinnerCount = 5
},
new Score
{
RulesetId = 0,
Accuracy = 1.0,
MaxCombo = 3220,
Statistics = new Statistics
{
Count300 = 2126
}
});

var osuPerfAttributes = result as OsuPerformanceAttributes;

Assert.NotNull(osuPerfAttributes);
Assert.Equal(455.90599187959032, osuPerfAttributes.Total);
Assert.Equal(141.45654132294621, osuPerfAttributes.Aim);
Assert.Equal(167.49667236961548, osuPerfAttributes.Speed);
Assert.Equal(140.70696717850745, osuPerfAttributes.Accuracy);
Assert.Equal(0.0000, osuPerfAttributes.Flashlight);
Assert.Equal(0.0000, osuPerfAttributes.EffectiveMissCount);
}
}
}
20 changes: 20 additions & 0 deletions Pettanko.Tests/Pettanko.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Pettanko\Pettanko.csproj" />
</ItemGroup>

</Project>
31 changes: 31 additions & 0 deletions Pettanko.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31912.275
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pettanko", "Pettanko\Pettanko.csproj", "{A5154878-72F7-4E36-9FB7-25B5C9E2B884}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pettanko.Tests", "Pettanko.Tests\Pettanko.Tests.csproj", "{1D2CD22C-6716-4707-8A6E-007F7D1A9FB4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A5154878-72F7-4E36-9FB7-25B5C9E2B884}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5154878-72F7-4E36-9FB7-25B5C9E2B884}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5154878-72F7-4E36-9FB7-25B5C9E2B884}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5154878-72F7-4E36-9FB7-25B5C9E2B884}.Release|Any CPU.Build.0 = Release|Any CPU
{1D2CD22C-6716-4707-8A6E-007F7D1A9FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D2CD22C-6716-4707-8A6E-007F7D1A9FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D2CD22C-6716-4707-8A6E-007F7D1A9FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D2CD22C-6716-4707-8A6E-007F7D1A9FB4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {73ADA6B4-4B6C-439B-89F6-49B0BC85CE5B}
EndGlobalSection
EndGlobal
84 changes: 84 additions & 0 deletions Pettanko/Calculators/CatchPerformanceCalculator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.

using System;
using System.Linq;
using Pettanko.Difficulty;
using Pettanko.Mods;
using Pettanko.Performance;

namespace Pettanko.Calculators
{
public class CatchPerformanceCalculator : IPerformanceCalculator
{
private int fruitsHit;
private int ticksHit;
private int tinyTicksHit;
private int tinyTicksMissed;
private int misses;

public PerformanceAttributes Calculate(DifficultyAttributes difficultyAttributes, Score scoreData)
{
var catchAttributes = (CatchDifficultyAttributes)difficultyAttributes;

fruitsHit = scoreData.Statistics.Count300;
ticksHit = scoreData.Statistics.Count100;
tinyTicksHit = scoreData.Statistics.Count50;
tinyTicksMissed = scoreData.Statistics.CountKatu;
misses = scoreData.Statistics.CountMiss;

// We are heavily relying on aim in catch the beat
double value = Math.Pow(5.0 * Math.Max(1.0, catchAttributes.StarRating / 0.0049) - 4.0, 2.0) / 100000.0;

// Longer maps are worth more. "Longer" means how many hits there are which can contribute to combo
int numTotalHits = totalComboHits();

double lengthBonus =
0.95 + 0.3 * Math.Min(1.0, numTotalHits / 2500.0) +
(numTotalHits > 2500 ? Math.Log10(numTotalHits / 2500.0) * 0.475 : 0.0);
value *= lengthBonus;

value *= Math.Pow(0.97, misses);

// Combo scaling
if (catchAttributes.MaxCombo > 0)
value *= Math.Min(Math.Pow(scoreData.MaxCombo, 0.8) / Math.Pow(catchAttributes.MaxCombo, 0.8), 1.0);

double approachRate = catchAttributes.ApproachRate;
double approachRateFactor = 1.0;
if (approachRate > 9.0)
approachRateFactor += 0.1 * (approachRate - 9.0); // 10% for each AR above 9
if (approachRate > 10.0)
approachRateFactor += 0.1 * (approachRate - 10.0); // Additional 10% at AR 11, 30% total
else if (approachRate < 8.0)
approachRateFactor += 0.025 * (8.0 - approachRate); // 2.5% for each AR below 8

value *= approachRateFactor;

if (scoreData.Mods.Any(m => m is ModHidden))
{
// Hiddens gives almost nothing on max approach rate, and more the lower it is
if (approachRate <= 10.0)
value *= 1.05 + 0.075 * (10.0 - approachRate); // 7.5% for each AR below 10
else if (approachRate > 10.0)
value *= 1.01 + 0.04 * (11.0 - Math.Min(11.0, approachRate)); // 5% at AR 10, 1% at AR 11
}

if (scoreData.Mods.Any(m => m is ModFlashlight))
value *= 1.35 * lengthBonus;

value *= Math.Pow(accuracy(), 5.5);

if (scoreData.Mods.Any(m => m is ModNoFail))
value *= 0.90;

return new CatchPerformanceAttributes
{
Total = value
};
}
private double accuracy() => totalHits() == 0 ? 0 : Extensions.Clamp((double)totalSuccessfulHits() / totalHits(), 0, 1);
private int totalHits() => tinyTicksHit + ticksHit + fruitsHit + misses + tinyTicksMissed;
private int totalSuccessfulHits() => tinyTicksHit + ticksHit + fruitsHit;
private int totalComboHits() => misses + ticksHit + fruitsHit;
}
}
10 changes: 10 additions & 0 deletions Pettanko/Calculators/IPerformanceCalculator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Pettanko.Difficulty;
using Pettanko.Performance;

namespace Pettanko.Calculators
{
public interface IPerformanceCalculator
{
PerformanceAttributes Calculate(DifficultyAttributes difficultyAttributes, Score scoreData);
}
}
Loading

0 comments on commit e1aa3ab

Please sign in to comment.