C#:Day03 코드 2021의 출현 - 바이너리 진단 사용

19195 단어 csharpadventofcode
Day03 이틀 전보다 요구가 높다.우리는 비트 서열을 분석하고 비트 위치와 주파수에 따라 정보를 추출해야 한다.
코드가 좀 지루하고 복잡해졌지만, 그다지 나쁘거나 복잡하지는 않았다.

제1부
이 퍼즐은 우리에게 비트 시퀀스 목록을 제공했다.이 데이터 집합에 근거하여 우리는 두 개의 값deltaepsilon을 계산하여 잠수함의 소모에 대응해야 한다.만약 우리가 데이터 집합을 2차원 비트 그룹으로 간주한다면, 더욱 쉽게 계산할 수 있을 것이다.delta값은 2차원 그룹의 열마다 가장 흔히 볼 수 있는 값을 지정함으로써 생성된 서열이다.epsilon값은 열마다 가장 흔치 않은 값의 서열이다.deltaepsilon의 값을 확정한 후에 우리는 반드시 이진수를 소수로 전환해야 한다.마지막으로 우리는 이 두 숫자의 곱셈이 필요하다.
이 해결 방안을 위해 알고리즘을 설계합시다.
POWER_CONSUMPTION(Values)
Input: A list of binary numbers
Output: The product of delta times epsilon values

FOR i=0 TO Length(Values[0])
    common += GetMostCommon(Values, i)
    uncommon += GetLeastCommon(Values, i)
ENDFOR

common = ConvertToDecimal(common)
uncommon = ConvertToDecimal(uncommon)

return common * uncommon
알고리즘이 완성되면 C# 구현을 시작하겠습니다.

시퀀스에서 특정 위치 가져오기
각 시퀀스의 위치를 열별로 검색하기 위해 GetBitsAt 방법을 만들었습니다.
private static string[] GetBitsAt(string[] sequence, int index)
{
    if (index > sequence[0].Length)
        throw new ArgumentOutOfRangeException(nameof(index));

    string[] bits = new string[sequence.Length];

    for (int i = 0; i < sequence.Length; i++)
    {
        bits[i] = sequence[i][index].ToString();
    }

    return bits;
}
이 방법은 문자열 그룹과 인덱스를 매개 변수로 받아들인다.
C#의 문자열은 Chars[] 속성을 제공합니다.이 속성은 문자열의 색인 위치에서 단일 Char 대상을 통해 접근할 수 있습니다.따라서, 우리는 서열 그룹의 모든 문자열에서 특정 문자에 접근할 수 있다.본질적으로, 우리는 서열 그룹을 2차원 문자 행렬로 볼 수 있다.
따라서 이 방법은 열 방식에 따라 서열을 교체할 수 있다.교체할 열은 제공된 index 매개 변수에 달려 있습니다.

계산 시퀀스에서 가장 흔히 볼 수 있는 원소
시퀀스 열에서 가장 일반적인 위치를 찾기 위해 MostCommon 방법을 만들었습니다.
public static string MostCommon(string[] sequence)
    => sequence.GroupBy(v => v)
               .OrderByDescending(g => g.Count())
               .First()
               .Key;
이 방법은 문자열 배열을 받아들이고 LINQ 조회 추출 시퀀스에서 가장 흔히 볼 수 있는 요소를 사용합니다.
우리들은 이 문제를 몇 부분으로 나누자.GroupBy(v => v): 서열 요소는 01로 나뉜다.OrderByDescending(g => g.Count()): 두 그룹은 각자의 원소 계수에 따라 내림차순으로 배열된다.First(): 첫 번째 그룹의 첫 번째 요소를 반환합니다.Key: 원소의 값을 추출한다.
이 두 가지 방법이 있으면 남은 해결 방안은 보잘것없게 변한다.
var gammaRate = "";
var epsilonRate = "";


for (int i = 0; i < data[0].Length; i++)
{
    string mostCommon = MostCommon(GetBitsAt(data, i));
    gammaRate += mostCommon;

    if (mostCommon.Equals("1"))
        epsilonRate += "0";
    else
        epsilonRate += "1";
}


var result = Convert.ToInt32(gammaRate, 2) * Convert.ToInt32(epsilonRate, 2);

제2부분
두 번째 부분에서 우리는 가장 흔하고 가장 흔하지 않은 위치를 다시 한 번 추적해야 한다.그러나 이번에 우리는 우리의 가치관을 창조하는 것이 아니라 일련의 기준을 바탕으로 그것들을 없애는 것이다.
우리는 다시 열 방식으로 서열을 두루 훑어보았다.산소발생기의 정해진 값을 찾는 과정은 이전 수수께끼에서 delta값을 생성하는 과정과 거의 같다.각 위치에서 가장 자주 사용하는 비트의 서열만 보존합니다.유일한 차이점은 0비트와 1비트의 수량이 같으면 1비트의 서열을 이 위치에 유지한다는 것이다.
이산화탄소 세척기의 정액치도 마찬가지다.각 위치에서 공통 비트가 가장 적은 시퀀스만 유지됩니다.이번에는 같은 상황에서 서열0을 이 위치에 유지한다.
나는 이전 수수께끼 중의 MostCommonGetBitAt 방법을 다시 사용했다.나는 이 해결 방안이 자랑스럽지 않다. 왜냐하면 일부 코드 복제가 있고, 일부 재구성은 틀림없이 질서정연하기 때문이다. 그러나 이것은 내가 처음 그것을 해결할 때 제기한 해결 방안이다.나는 이것이 경쟁적인 프로그래밍의 결점이라고 생각한다.
여기에는 세 가지 새로운 방법이 있다.HasMostCommon 방법은 주어진 서열이 이 위치에서 가장 흔히 볼 수 있는 위치가 있는지 검사한다.
private static bool HasMostCommon(string sequence, string bit, int position)
    => sequence[position].ToString().Equals(bit);
GetOxygenRatingGetCO2Rating는 각각 산소와 이산화탄소의 정해진 값을 귀속 방식으로 계산한다.
private static string GetOxygenRating(string[] sequences, int index)
{
    if (sequences.Length == 1)
        return sequences[0];

    string mostCommon = Utils.MostCommon(GetBitsAt(sequences, index));

    List<string> common = new();
    List<string> uncommon = new();

    foreach (var sequence in sequences)
    {
        if (HasMostCommon(sequence, mostCommon, index))
            common.Add(sequence);
        else
            uncommon.Add(sequence);
    }

    if (common.Count == uncommon.Count)
        if (uncommon[0][index].ToString().Equals("1"))
            return GetOxygenRating(uncommon.ToArray(), index + 1);

    return GetOxygenRating(common.ToArray(), index + 1);
}
private static string GetCO2Rating(string[] sequences, int index)
{
    if (sequences.Length == 1)
        return sequences[0];

    string mostCommon = Utils.MostCommon(GetBitsAt(sequences, index));

    List<string> common = new List<string>();
    List<string> uncommon = new List<string>();

    foreach (var sequence in sequences)
    {
        if (HasMostCommon(sequence, mostCommon, index))
            common.Add(sequence);
        else
            uncommon.Add(sequence);
    }

    if (common.Count == uncommon.Count)
        if (common[0][index].ToString().Equals("0"))
            return GetCO2Rating(common.ToArray(), index + 1);

    return GetCO2Rating(uncommon.ToArray(), index + 1);
}
HasMostCommon 방법은 주어진 서열이 이 위치에서 가장 흔히 볼 수 있는 위치가 있는지 검사한다.
해결 방안의 나머지 부분은 다시 보잘것없게 변했다.
string oxygen = GetOxygenRating(data, 0);
string co2 = GetCO2Rating(data, 0);

var result = (Convert.ToInt32(oxygen, 2) * Convert.ToInt32(co2, 2))

이 사람들만!
셋째 날은 여기까지야.나는 이 코드에 대해 그다지 만족하지 않는다.그것은 틀림없이 약간의 재구성과 정리가 필요하지만, 경쟁적인 프로그래밍에서는 때때로 실현 속도를 위해 형식을 희생해야 한다.
나는 내가 당신들에게 나의 해결 방안이 어떻게 작동하는지 더욱 깊이 있는 설명을 제공할 수 있기를 바랍니다.
myGithub Repo에서 이 해결 방안과 다른 해결 방안을 찾을 수 있습니다.
재미있게 놀았으면 좋겠습니다. 다음 회'코드 2021'에서 만나요!

좋은 웹페이지 즐겨찾기