볼링 점수 계산
생각보다 볼링 점수 계산기를 코드로 짜보려니 예상치 못한 문제들이 많았다.
- 스트라이크 이후에 공 2개의 점수를 보너스로 받는다.
- 스페어 이후에 공 1개의 점수를 보너스로 받는다.
- 10 프레임에서 달성한 스트라이크, 스페어에 대해서는 보너스를 받지 못한다.
- 10 프레임에서 스트라이크, 스페어를 달성하면 1번 더 공을 던질 수 있다.
볼링 점수 계산 사이트
예제 코드
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace backjun
{
public class Bowling
{
private (int, int, int, int)[] m_score;
private List<Action<int>> m_action = new();
private int m_frame;
private int m_ballCount;
private const int STRIKE = 10;
private const int SPARE = 10;
private const int LAST_FRAME = 9;
public Bowling()
{
m_score = new (int, int, int, int)[10];
m_frame = 0;
m_ballCount = 0;
}
public void ThrowBall(int pin)
{
var frame = m_frame;
if (m_ballCount == 0)
{
m_score[m_frame].Item1 = pin;
}
else if (m_ballCount == 1)
{
m_score[m_frame].Item2 = pin;
}
else
{
m_score[m_frame].Item3 = pin;
}
m_score[m_frame].Item4 += pin;
m_ballCount++;
foreach (var func in m_action.ToList())
{
func.Invoke(pin);
m_action.Remove(func);
}
if (m_frame < LAST_FRAME)
{
if (m_score[m_frame].Item1 == STRIKE)
{
m_action.Add(pin =>
{
m_score[frame].Item4 += pin;
m_action.Add(pin => m_score[frame].Item4 += pin);
});
}
else if (m_score[m_frame].Item1 + m_score[m_frame].Item2 == SPARE)
{
m_action.Add(pin => m_score[frame].Item4 += pin);
}
if (pin == 10 || m_ballCount == 2)
{
m_frame++;
m_ballCount = 0;
}
}
}
public int TotalScore()
{
int sum = 0;
foreach (var i in m_score)
{
sum += i.Item4;
}
return sum;
}
}
public class Program
{
static void Main(string[] args)
{
var bowling = new Bowling();
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
bowling.ThrowBall(10);
Debug.Assert(bowling.TotalScore() == 300);
var bowling1 = new Bowling();
bowling1.ThrowBall(8);
bowling1.ThrowBall(2);
bowling1.ThrowBall(5);
bowling1.ThrowBall(4);
bowling1.ThrowBall(5);
bowling1.ThrowBall(4);
bowling1.ThrowBall(10);
bowling1.ThrowBall(10);
bowling1.ThrowBall(10);
bowling1.ThrowBall(10);
bowling1.ThrowBall(10);
bowling1.ThrowBall(10);
bowling1.ThrowBall(9);
bowling1.ThrowBall(1);
bowling1.ThrowBall(1);
Debug.Assert(bowling1.TotalScore() == 213);
}
}
}
함수포인터를 이용해서 스트라이크, 스페어 달성시에 정보를 저장해 뒀다가 다음 투구시에 해당 점수를 정해지면 콜백으로 계산하였다.
특이한 람다 코드(이것이 함수형 프로그래밍?)
m_action.Add(pin =>
{
m_score[frame].Item4 += pin;
m_action.Add(pin => m_score[frame].Item4 += pin);
});
델리게이트 안에서 델리게이트 추가하는 특이한 형태의 코드를 작성해봤다. 문제없이 잘 돌아가고 코드도 깔끔해졌다. 논리적으로도 맞아서 기분이 좋아졌다. (*delegate 체인이 이런 형태이지 않을까라는 생각을 했다. or 함수형 프로그래밍)
참고 사이트
'프로그래밍 > C#' 카테고리의 다른 글
C# Virtual vs Abstract (0) | 2024.02.03 |
---|---|
C# 변수 캡처(Capture)에 대해서 (1) | 2024.01.23 |
C# 문자열 정렬하기 (0) | 2024.01.15 |
C# Call by value와 Call by reference에 대해서 (0) | 2024.01.12 |
C# String은 참조 타입(Reference type)이면서 불변(Immutable)하다. (1) | 2024.01.10 |
댓글