기획 

 타일 : 9 X 9 , 타일종류 : 5개

 1. 가로 세로로 3개 이상 동일한 문양이 연속되어 있다면 제거된다.

 2. 제거되는 문양은 각각 한 타일당 10점이다.

 3. 동시에 여러 문양의 연쇄가 발생한다면, 모두 제거되고, 동일한 콤보의 점수 (1콤보일때 10점)로 판정한다.

 4. 제거된 뒤에는 위에서부터 한 칸씩 내려온다. 빈 공간에는 새로운 문양들이 내려온다.

 5. 빈 공간이 다 채워진 뒤에도 가로 세로 3개 이상 동일한 문양이 있다면 제거되며 이후 부터는 콤보로 친다. (2콤보 - 20점)



플로우

1. 최초 시작시 9x9의 타일에 각각 랜덤한 타일을 생성한다.

2. 최초에는 전체 타일에 대해 3 매칭 판단을 해야한다.

 2-1)왼쪽부터 오른쪽으로 , 위부터 아래로 차례로 매칭 비교한다. ( 한 타일당 2번비교될듯.  총 162번)

 2-2) 각 타일별로 매칭 판별을 한다. (동서남북 - 한타일당 4번 비교)

 2-3) 2번 스타일로 하되, 동일한 크기의 bool 배열을 만들어 방문한 곳을 체크해 다시 체크하지 않도록 한다. 하나의 라인을 지나가며 주변의 자신과 같은 타일은 큐에 넣고, 매칭 라인을 돌면 큐에서 빼내며 다른 연결된 매칭라인이 있는지 확인한다.  결국 전체 타일을 돌아야한다. 2번에 비해서는 절약할 수 있으나, 1번과는 큰 차이가 없다. (오히려 더 연산이 많아 보인다.)

3. 매칭은 별도로 저장한다.

 3-1 ) 저장 방법 - 하나의 구조체가 가로세로여부, 시작 인덱스와 종료인덱스를 저장. 리스트 형식으로 해당 구조체를 저장.

3-2) - 각각의 매칭된 타일들을 모두 저장한다. 중복을 허용하지 않기위해 set (hashSet)으로 저장.

4. 저장된 매칭 리스트를 제거한다.

5. 빈 공간의 위에있는 타일들을 내려 빈 공간을 채우고, 남은 최상위의 빈 공간에 새로운 타일을 랜덤하게 생성하여 리필한다. 

 - 5-1)  아래에서 위로 탐색하여 빈공간이 나올때마다 내려가야할 칸 ++ 하여 내린다.

 - 5-2) 우리는 제거된 타일의 위치를 알고있다. 그러면 제거된 타일의 위치의 위에 타일들에 +1을 해주면 내려가야 할 칸을 알 수 있다. 이 값을 기반으로 타일을 내려준다.

 - 5-3) 1+2 형식으로 제거된 타일의 세로좌표만 1번 방식으로 진행한다. ( 2번 방식으로는 세로영역에 제거된 라인이 겹칠수록 비효율적인 연산이 늘어난다.)

    리필할 때 새로 타일을 생성하는 것에 사용할 것까지 생각하여 5-3으로 진행합니다.

6. 매칭 리스트가 0이 될때까지 2~5 반복.

 - 매칭 리스트가 0이면 매칭 할 게 더이상 없는지 확인.

- 아래 두 형태가 있는지를 확인하면 되겠네요.총 연산은 대략162*8 = 1296 정도 되겠네요.

                    


  - 매칭할게 없다면 1번으로 되돌아간다.


7. 유저 타일 터치 후 드래그 시 방향 판별을 통해 해당 방향의 타일과 swap하는 형태를 보여주고, 터치를 종료시 swap한다. ( 일정 길이 이상)

8. 유저가 타일을 변경한 경우 두 개의 타일에 대해서 4방향 매칭 판별을 진행한다.

 ( 동일한 문양의 타일일 경우 동일한 방향으로 연쇄 확인)

9. 매칭이 되지 않았을 경우 두 타일을 다시 swap 한다.

10. 매칭이 될 경우 3~5를 진행하고, 6번을 진행한다.


생각할만한 점 :

  •  2번의 알고리즘을 좀 더 개선할 방법은 없을까?  고려 - 마스크 기법
    • 2-1 방법은 총 162번의 연산을 하는데, 마스크 방식으로 하면 마스크에 따라 배수로 늘지 않을까..
  •  더이상 매칭될수 없다면? 단순하게 재배열 ㄱㄱ
  •  매칭할 수없는지 확인하는 로직을 개선할 방법은 없을까?



* 지적은 언제나 환영입니다.

Posted by 검은거북

abstract 란?

abstract 한정자의 의미는 abstract가 사용되는 곳에 누락되거나 불완전한 구현이 있다는 것을 의미합니다. 즉, 파생 클래스에서 그 불완전하거나 누락된 부분을 구현해야하는거죠. abstract 클래스의 목적은 여러 파생 클래스에서 공유할 수 있는 기본 클래스의 공통적인 정의를 제공하는 것입니다. 일반적으로는 클래스로 묶을 때, 하위 클래스가 반드시 구현해야하는 규칙을 명시하거나 상위 클래스를 통해 접근하고자 할 때 사용하는 것으로 알고있습니다.

쉽게 생각하면 골자만 만들어진 설계도 정도로 보면 되지 않을까요. 자동차를 예를 들면 차는 문이 있고 운전대와 좌석이 있어야 한다. (여기까지가 abstract) 차 종류별로 위의 규칙은 지키되 문이 위로 열릴수도 옆으로 열릴수도 있게끔 만드는 거죠. (하위 클래스의 구현)


특징

  • abstract 한정자는 클래스, 메서드, 프로퍼티, 인덱서, 이벤트와 함께 사용가능하다.
  • abstract가 사용되면 파생클래스에서 구현되어야 한다.
  • 추상 클래스 (abstract class)
    • 추상 클래스는 인스턴스화 될 수 없다.
      • 변수와 메서드 선언은 일반 클래스와 동일하게 할 수 있다. (물론 virtual도 사용가능)
    • 상속을 제한하는 sealed와는 같이 사용할 수 없다.
  • 추상 메서드 (abstract method)
    • 추상 메서드의 선언은 추상 클래스에서만 허용된다.
    • 추상 메서드는 암시적으로 가상(virtual) 함수이다. 
      • 기본적으로 동작은 virtual 함수와 같지만, virtual과 달리 abstract는 파생 클래스에서 반드시 구현해야한다.
    • 추상 메서드는 구현부가 존재하지 않는다. ex) public abstract void test();
    • 파생 클래스에서는 동일한 시그니쳐 메서드에 override 키워드를 통해 재정의한다.
    • private, static, virtual 키워드와는 사용 불가능하다.


예제


    
    public abstract class Monster
    {
        public int hp;
        public void setHp(int _hp)
        {
            hp = _hp;
        }
        public abstract void hit();
    }

    public class Orc : Monster
    {
        
        public override void hit()
        {
            Console.WriteLine("Orc hit HP: " + hp);
        }
    }

    public class Elf : Monster
    {
        public override void hit()
        {
            Console.WriteLine("Elf hit HP: " + hp);
        }
    }

Monster를 abstract 클래스로 만들고,  setHp라는 일반 메서드와 hit라는 추상 메소드를 선언했습니다.

Orc와 Elf는 Monster를 상속받아 hit를 재정의 하고 있습니다.

상속받는 클래스에서 hit를 override하지 않으면 오류가 발생합니다.

    
        static void Main(string[] args)
        {
            Orc monster1 = new Orc();
            Elf monster2 = new Elf();

            monster1.setHp(10);
            monster1.hit();
            monster2.setHp(20);
            monster2.hit();

            Monster monster3 = new Orc();
            Monster monster4 = new Elf();


            Console.WriteLine("////////////////////");
            monster3.setHp(30);
            monster3.hit();
            monster4.setHp(40);
            monster4.hit();

        }


위는 각 클래스 변수에 해당 클래스의 인스턴스를 담고, 아래는 Monster 변수에 하위 클래스 인스턴스를 담고 있습니다.

어느쪽도 abstract에서 구현된 setHp 함수가 잘 동작하고, hit역시 상속받은대로 잘 동작되고있습니다.

abstract 클래스는 자기 자신을 인스턴스로 삼을 수 없습니다.


abstract 의 활용

 이전 포스팅인 virtual에서 언급되었듯이 abstract는 여러 클래스들이 공통적으로 가져야 할 특징들을 정의해 놓는 것이죠. virtual과 크게 다른 점은 virtual은 선택형이고, abstract는 반드시 구현해야 한다는 점과 인스턴스로써 만들 수 있냐의 차이입니다. 때문에 abstract는 몬스터의 hit, attack, move 등 모든 몬스터가 반드시 가져야 할 함수를 선언하여 몬스터라는 그룹을 정의 할 때 쓰입니다.  모든 몬스터가 공통적으로 행동해야하는 함수라면 미리 구현을 하고, 모든 몬스터가 공통적으로 가지되 개별적으로 동작해야하는 함수라면 abstract로 선언하여 상속시 반드시 구현하도록 하죠. 

 예를들어 abstract를 활용해 RPG 게임의 몬스터를 만든다고 생각해보죠. 가장 상위 클래스인 Monster는 타격시 호출되는 Hit는 공통적으로 쓰기위해 구현하고, 나머지 move와 attack은 하위 클래스가 반드시 구현할 수 있도록 abstract로 만듭니다. 그리고 선공형, 비선공형 몬스터로 소분류를 만들어 Move에서 적을 쫒거나 무시하는 로직을 추가해 구현을 하고, 그 하위로 세부 몬스터인 Orc나 Slime에서 특징에 따라 Attack을 만듭니다. ( 몬스터별로 얼음을 쓰기도 독을 쓰기도 하니까요.)

  
    public abstract class Monster
    {
        public void Hit()
        {
            //Do Hit;
        }
        public abstract void Move();
        public abstract void attack();
    }
    
    public abstract class AggressiveMonster:Monster
    {
        public override void Move()
        {
            //Move Aggressive
        }
    }
    
    public class Slime:AggressiveMonster
    {
        public override void attack()
        {
            //Attack with poison
        }
    }

 이런식이지 않을까요. 이렇게 하게 몬스터를 분류별로 나누어 유지보수가 용이해지고, 다른 클래스를 작성하는 사람 입장에서는 Monster 클래스만 보고 어떤 함수를 호출해야할지 감을 잡을 수 있죠.

 * 활용 예시는 지극히 개인적인 생각입니다. 혹시 문제가 있거나 잘못된 점이 있으면 말씀부탁드립니다.


Posted by 검은거북

MSDN에서 여기저기 뒤져보다가 좋은 것을 찾았습니다. 물론 저한테 좋은거요.


https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/inside-a-program/coding-conventions


MS에서 말하는 C# 코딩 규칙입니다. 


저는 개인적으로 코딩 규칙에 대해서 평소에 "대체 뭐가 맞는거야!?" 하는 생각이 있었거든요. 대학교 교수님이 말한 것과 이전 회사 시니어가 말한 것과 팀장님이 말한 것 매번 저게 옳다, 그딴 식으로 하지마라를 상반되게 들어서 우왕좌왕하게 되더라고요....ㅠㅠ 

이제는 MS에서 권장하는 규칙을 알았으니 MS에서 권장하는 코딩 대로 밀고 나가야죠ㅎㅎ ( 또 뭐라 그러면 만든사람이 그렇게 하래요 라고 똭! 무려 모범사례입니다!!)


내용은...대부분이 보기 좋은 코딩을 위한 내용이더군요.. 애초에 맨 위에 용도에서도 유지보수의 용이함을 내놓기도 하고 있네요.


 당연한 내용들이 대부분이긴 한데 내용을 보면서 드는 의문점이 "var를 의외로 자주쓰고, 권장한다?" 대체 var가 동작이 어떻게 되길래? 굳이 암시적을? 입니다. 특히 오른쪽에 변수 형식이 명확하거나 정확한 형식이 중요하지 않으면 var를 사용한다고 하는데....변수 형식이 명확한데 굳이 왜 var를 쓰지 라는 생각이 드네요....;;;

 그래서 좀 더 다른 섹터의 글들을 찾아보니, var는 편리함을 위해서 사용할 뿐이고, 다른 개발자가 보기에 더 이해하기 어렵기 때문에 꼭 필요할 때만 쓰라고 하네요. 음.....;;;

  (출처 : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables)


상반되는 느낌이네요....

(지역변수에서)

1, 변수 형식이 명확하면 사용한다.

2. 정확한 형식이 중요하지 않으면 사용한다.

3. 다른 개발자가 보기에 더 이해하기 어렵기 때문에 꼭 필요할 때 사용한다.


인데, 다시 읽어보니... 

 1번은 중의적으로 해석될 수 있는 변수 형식에는 쓰지 말란 소리고, 명확한 변수 형식이기 때문에 var를 써서 편리함과 코드 가독성에 이득을 취하라는 말이더군요.

 2번은 거꾸로 말하면 정확한 형식이 중요하면 사용하지 말란건데, 암시적 형식이니까 당연한 말이고... 

 그럼 3번의 꼭 필요하다는 곳은 1,2번에 포함되고 코드 가독성 향상이 필요한 곳을 말하는 걸까요?


 그래서 제 결론은 var는 지역 변수를 사용함에 변수 형식이 명확하하거나 정확한 형식이 중요하지 않은 곳에서 코드 가독성 향상이 필요하다면 사용하기를 권장한다. 라는 것 같네요...


맞나.. 혹시 다른 의견 있으시거나 잘못된 점이 있다면 지적 부탁드립니다 ㅠ 


Posted by 검은거북

블로그 이미지
프로그래밍 공부 요약 및 공부하며 발생한 궁금증과 해결과정을 포스팅합니다.
검은거북

공지사항

Yesterday
Today
Total

달력

 « |  » 2025.2
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28

최근에 올라온 글

최근에 달린 댓글

글 보관함