본문 바로가기
프로그래밍/C#

C# 볼링 점수 계산기(Bowling Score Calculator)

by bantomak 2024. 1. 19.

볼링 점수 계산

생각보다 볼링 점수 계산기를 코드로 짜보려니 예상치 못한 문제들이 많았다.

 

  • 스트라이크 이후에 공 2개의 점수를 보너스로 받는다.
  • 스페어 이후에 공 1개의 점수를 보너스로 받는다.
  • 10 프레임에서 달성한 스트라이크, 스페어에 대해서는 보너스를 받지 못한다.
  • 10 프레임에서 스트라이크, 스페어를 달성하면 1번 더 공을 던질 수 있다.

 

볼링 점수 계산 규칙

 

볼링 점수 계산 사이트

 

Bowling Score Calculator

THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE

www.bowlinggenius.com

 

예제 코드

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 함수형 프로그래밍)

 

참고 사이트

 

생활체육따라하기 | 볼링 | 볼링 | 기초지식 | 점수계산방법

HOME > 볼링 > 기초지식 > 점수계산방법 점수계산방법 --> --> 스트라이크 각 프레임의 제1투구에서 10개 핀이 전부 넘어지게 되면 '스트라이크'가 된다. 이때, 스트라이크의 득점은 10점이며, 보너스

sports.koreanpc.kr:9000

댓글