<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Hello World</title>
    <link>https://eskeptor.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 28 Jun 2026 10:39:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Eskeptor</managingEditor>
    <image>
      <title>Hello World</title>
      <url>https://tistory1.daumcdn.net/tistory/2549417/attach/28640c1df11d4028a5254b313c037aed</url>
      <link>https://eskeptor.tistory.com</link>
    </image>
    <item>
      <title>[C++11] 이동 생성자(Move Constructors)와 이동 할당 연산자(Move Assignment Operators)</title>
      <link>https://eskeptor.tistory.com/203</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vaOX7/btsK4aWCCBr/xbqKnJgfKv925AxhmTsD8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vaOX7/btsK4aWCCBr/xbqKnJgfKv925AxhmTsD8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vaOX7/btsK4aWCCBr/xbqKnJgfKv925AxhmTsD8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvaOX7%2FbtsK4aWCCBr%2FxbqKnJgfKv925AxhmTsD8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++11에 들어서서 rvalue (Right-value)에 대한 기능(?)들이 생기기 시작 했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 중에서 &lt;code&gt;이동 생성자(Move Constructors)&lt;/code&gt;와 &lt;code&gt;이동 할당 연산자(Move Assignment Operators)&lt;/code&gt;에 대한 이야기 입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;기본 레퍼런스 내용&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1733037458992&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;How to: Define move constructors and move assignment operators (C++)&quot; data-og-description=&quot;Learn more about: Move Constructors and Move Assignment Operators (C++)&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170&quot; data-og-url=&quot;https://learn.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cDdpFQ/hyXDef5M8Q/AA2msfKmyubWJL5biJ9Wy0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/en-us/cpp/cpp/move-constructors-and-move-assignment-operators-cpp?view=msvc-170&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cDdpFQ/hyXDef5M8Q/AA2msfKmyubWJL5biJ9Wy0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;How to: Define move constructors and move assignment operators (C++)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn more about: Move Constructors and Move Assignment Operators (C++)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금부터 나올 이야기는 위의 MS Learn(구 MSDN)에 나온 이야기와 기타 공부를 했었던 내용의 짬뽕입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;rvalue (Right-value)와 lvalue (Left-value)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이야기를 다루기 위해서는 &lt;code&gt;rvalue&lt;/code&gt;와 &lt;code&gt;lvalue&lt;/code&gt;에 대해서 먼저 이야기해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통상적으로 &lt;code&gt;Right-value&lt;/code&gt;를 뜻하는 &lt;code&gt;rvalue&lt;/code&gt;는 &lt;code&gt;리터럴(Literal)&lt;/code&gt; 혹은 &lt;code&gt;임시 객체(Temporary Object)&lt;/code&gt;라고 불리우는 그것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 쉽게 말해서 &lt;code&gt;주소값, 레퍼런스화 할 수 없는 값&lt;/code&gt;입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733037946124&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int nNum = 33;   // 33은 rvalue&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 흔히 Right-side에 오는 값이어서 &lt;code&gt;Right-value&lt;/code&gt;라고 불리웁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 위에서 말했듯이 오른쪽에 오는 &lt;code&gt;리터럴(Literal)&lt;/code&gt; 혹은 &lt;code&gt;임시 객체(Temporary Object)&lt;/code&gt;에만 해당하는 값만 &lt;code&gt;rvalue&lt;/code&gt;라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 &lt;code&gt;lvalue&lt;/code&gt;는 &lt;code&gt;rvalue&lt;/code&gt;의 반대 개념이겠죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;code&gt;주소값을 취할 수 있는, 레퍼런스화 할 수 있는 값&lt;/code&gt;을 말합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733038144284&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int nNum = 33;     // nNum은 lvalue
int&amp;amp; nlNum = nNum; // nNum은 lvalue임으로 레퍼런스를 취할 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 이렇게 위의 예제에서 &lt;code&gt;nlNum&lt;/code&gt;이라는 레퍼런스 변수에 대입할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Left-side에 오는 값이어서 &lt;code&gt;Left-value&lt;/code&gt;라고 불립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;code&gt;lvalue&lt;/code&gt;가 Right-side에 간다고 해서 &lt;code&gt;rvalue&lt;/code&gt;가 되지는 못합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(그 이유는 rvalue에서 설명 했습니다.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이동 생성자 (Move Constructors)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 생성자의 경우 &lt;code&gt;rvalue 참조 선언자(&amp;amp;&amp;amp;)&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733040971392&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass
{
public:
    /**
     * @brief   Copy constructor
     * @param   cls         복사 대상인 데이터
     */
    MyClass(const MyClass&amp;amp; cls)
    {
        m_nLength = cls.m_nLength;
        m_pszName = new char[m_nLength + 1];
        ::strcpy_s(m_pszName, m_nLength + 1, cls.m_pszName);

        std::cout &amp;lt;&amp;lt; &quot;복사 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }
    
    /**
     * @brief   Move constructor (noexcept를 선언해주어야 함)
     * @param   cls         이동 대상인 데이터 (rvalue 참조 선언자)
     */    
    MyClass(MyClass&amp;amp;&amp;amp; cls) noexcept
    {
        m_pszName = cls.m_pszName;
        m_nLength = cls.m_nLength;
        
        cls.m_nLength = 0;
        cls.m_pszName = nullptr;    // 제거하지 못하도록 nullptr로 바꾸어버림

        std::cout &amp;lt;&amp;lt; &quot;이동 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }
    
    /**
     * @brief   Deconstructor
     */
    ~MyClass() noexcept
    {
        delete[] m_pszName;
    }
    
    /* 생략 */
private:
    int m_nLength;      // 문자열 데이터의 길이 (\0 제외)
    char* m_pszName;    // 문자열 데이터
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 생성자의 경우 &lt;code&gt;rvalue 참조 선언자(&amp;amp;&amp;amp;)&lt;/code&gt;로 이동할 인자를 받고 내부에서는 이동하도록 코드를 짜줍니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;위의 경우에는 이동할 데이터인 cls가 현재 생성되는 데이터로 문자열 데이터(m_pszName)을 넘겨주고 cls 내부의 문자열 데이터(m_pszName)을 nullptr로 바꾸어 줌으로써 cls가 소멸할 때 이동한 데이터를 제거하지 못하도록 합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 해당 이동 생성자의 경우 &lt;code&gt;noexcept&lt;/code&gt; 이어야만 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이동&amp;nbsp;할당&amp;nbsp;연산자(Move&amp;nbsp;Assignment&amp;nbsp;Operators)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 할당 연산자의 경우에도 이동 생성자와 유사합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733042180223&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @brief   Move assignment operator
 * @param   cls         이동 대상인 데이터
 * @return  
 */
MyClass&amp;amp; operator=(MyClass&amp;amp;&amp;amp; cls) noexcept
{
    if (this != &amp;amp;cls)
    {
        delete[] m_pszName;

        m_pszName = cls.m_pszName;
        m_nLength = cls.m_nLength;

        cls.m_nLength = 0;
        cls.m_pszName = nullptr;  // 제거하지 못하도록 nullptr로 바꾸어버림
    }
    return *this;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이동 할당 연산자에도 &lt;code&gt;rvalue 참조 선언자(&amp;amp;&amp;amp;)&lt;/code&gt;로 선언되며 이 또한 &lt;code&gt;noexcept&lt;/code&gt; 이어야만 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;여기까지의 예제&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 만든 &lt;code&gt;MyClass&lt;/code&gt;는 아래와 같습니다.&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;pre id=&quot;code_1733042502894&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;

class MyClass
{
public:
    /**
     * @brief   Copy constructor (문자열 복사)
     * @param   pszName     복사할 문자열
     */
    MyClass(const char* pszName)
    {
        m_nLength = static_cast&amp;lt;int&amp;gt;(::strlen(pszName));
        m_pszName = new char[m_nLength + 1];
        ::strcpy_s(m_pszName, m_nLength + 1, pszName);

        std::cout &amp;lt;&amp;lt; &quot;문자열 복사 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }

    /**
     * @brief   Move constructor (noexcept를 선언해주어야 함)
     * @param   cls         이동 대상인 데이터 (rvalue 참조 선언자)
     */
    MyClass(MyClass&amp;amp;&amp;amp; cls) noexcept
    {
        m_pszName = cls.m_pszName;
        m_nLength = cls.m_nLength;
        cls.m_nLength = 0;
        cls.m_pszName = nullptr;

        std::cout &amp;lt;&amp;lt; &quot;이동 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }
    /**
     * @brief   Copy constructor
     * @param   cls         복사 대상인 데이터
     */
    MyClass(const MyClass&amp;amp; cls)
    {
        m_nLength = cls.m_nLength;
        m_pszName = new char[m_nLength + 1];
        ::strcpy_s(m_pszName, m_nLength + 1, cls.m_pszName);

        std::cout &amp;lt;&amp;lt; &quot;복사 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }

    /**
     * @brief   Deconstructor
     */
    ~MyClass()
    {
        delete[] m_pszName;
        m_pszName = nullptr;
    }

    /**
     * @brief   Move assignment operator
     * @param   cls         이동 대상인 데이터
     * @return  
     */
    MyClass&amp;amp; operator=(MyClass&amp;amp;&amp;amp; cls) noexcept
    {
        if (this != &amp;amp;cls)
        {
            delete[] m_pszName;

            m_pszName = cls.m_pszName;
            m_nLength = cls.m_nLength;

            cls.m_nLength = 0;
            cls.m_pszName = nullptr;
        }
        return *this;
    }

private:
    int m_nLength;      // 문자열 길이
    char* m_pszName;    // 문자열 데이터 (new 하는 데이터로 소멸자에서 제거 예정)
};

int main(void)
{
    MyClass cls1(&quot;Hello&quot;);              // 문자열 복사 생성자
    MyClass clsCopy = cls1;             // 복사 생성자
    MyClass clsMove = std::move(cls1);  // 이동 생성자

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;자동으로 생성되는 이동 생성자 및 이동 할당 연산자&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 항상 이동 생성자와 이동 할당 연산자를 구현해야 할까요?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;If a class doesn't define a move constructor, the compiler generates an implicit one if there's no user-declared copy constructor, copy assignment operator, move assignment operator, or destructor. If no explicit or implicit move constructor is defined, operations that would otherwise use a move constructor use the copy constructor instead. If a class declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted.&lt;br /&gt;출처: https://learn.microsoft.com/en-us/cpp/cpp/constructors-cpp?view=msvc-170#move_constructors&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 내용을 보면 &lt;b&gt;클래스가 이동 생성자를 정의하지 않았으며 사용자가 복사 생성자, 복사 할당 연산자, 이동 할당 연산자 또는 소멸자를 선언하지 않은 경우 경우 암시적 생성자를 생성한다&lt;/b&gt;고 되어있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733043474556&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MyClass(const MyClass&amp;amp; other);             // 복사 생성자
MyClass&amp;amp; operator=(const MyClass&amp;amp; other);  // 복사 할당 연산자
MyClass(MyClass&amp;amp;&amp;amp; other);                  // 이동 생성자
MyClass&amp;amp; operator=(MyClass&amp;amp;&amp;amp; other);       // 이동 할당 연산자
~MyClass();                                // 소멸자&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 위와 같이 선언하지 않았다면 자동으로 생성을 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 &lt;u&gt;&lt;b&gt;참조형 변수가 있는 경우에 자동으로 생성해주지 않습니다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;A defaulted copy/move assignment operator for class X is defined as deleted if X has: &lt;br /&gt;- a variant member with a non-trivial corresponding assignment operator and X is a union-like class, or &lt;br /&gt;- a non-static data member of const non-class type (or array thereof), or&lt;br /&gt;- a non-static data member of reference type, or&lt;br /&gt;- a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M&amp;rsquo;s corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or &lt;br /&gt;- a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B&amp;rsquo;s corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or &lt;br /&gt;- for the move assignment operator, a non-static data member or direct base class with a type that does not have a move assignment operator and is not trivially copyable, or any direct or indirect virtual base class. &lt;br /&gt;&lt;br /&gt;출처: C++ International Standard N3242(C++11) 12.8 Copying and moving class objects, 24번&lt;br /&gt;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이동과 같이 사용하는 함수) std::move 함수&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 봤던 여기까지의 예제 에서 &lt;code&gt;main 함수&lt;/code&gt;에서 &lt;code&gt;std::move&lt;/code&gt;라는 함수를 봤을 겁니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;77&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QLakY/btsK2mxsLfC/XaKQWfShgDCJ5tJcG5EGw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QLakY/btsK2mxsLfC/XaKQWfShgDCJ5tJcG5EGw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QLakY/btsK2mxsLfC/XaKQWfShgDCJ5tJcG5EGw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQLakY%2FbtsK2mxsLfC%2FXaKQWfShgDCJ5tJcG5EGw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;810&quot; height=&quot;77&quot; data-origin-width=&quot;810&quot; data-origin-height=&quot;77&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;std::move 함수&lt;/code&gt;를 썼을 때는 이동 생성자로, 그렇게 하지 않았을 때는 복사 생성자로 유도되는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mDeM2/btsK4eLtr8M/KI4iJDlea269Qlodr2gVa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mDeM2/btsK4eLtr8M/KI4iJDlea269Qlodr2gVa1/img.png&quot; data-alt=&quot;출처: https://en.cppreference.com/w/cpp/utility/move&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mDeM2/btsK4eLtr8M/KI4iJDlea269Qlodr2gVa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmDeM2%2FbtsK4eLtr8M%2FKI4iJDlea269Qlodr2gVa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;766&quot; height=&quot;344&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://en.cppreference.com/w/cpp/utility/move&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;std::move 함수&lt;/code&gt;는 해당 object가 이동할 수 있음을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;암시&lt;/b&gt;&lt;/span&gt;만 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이동 생성자 또는 이동 할당 연산자가 선언되어 있지 않다면 이동이 아닌 복사를 수행할 수도 있다는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;b&gt;무조건 이동을 보장하지는 않는다는 것이지요.&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위의 &lt;code&gt;MyClass&lt;/code&gt;에서 이동 생성자와 이동 할당 연산자를 제거하면 &lt;code&gt;std::move함수&lt;/code&gt;를 호출해도 복사만 수행하게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1733045300457&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;

class MyClass
{
public:
    /**
     * @brief   Copy constructor (문자열 복사)
     * @param   pszName     복사할 문자열
     */
    MyClass(const char* pszName)
    {
        m_nLength = static_cast&amp;lt;int&amp;gt;(::strlen(pszName));
        m_pszName = new char[m_nLength + 1];
        ::strcpy_s(m_pszName, m_nLength + 1, pszName);

        std::cout &amp;lt;&amp;lt; &quot;문자열 복사 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }

    /**
     * @brief   Copy constructor
     * @param   cls         복사 대상인 데이터
     */
    MyClass(const MyClass&amp;amp; cls)
    {
        m_nLength = cls.m_nLength;
        m_pszName = new char[m_nLength + 1];
        ::strcpy_s(m_pszName, m_nLength + 1, cls.m_pszName);

        std::cout &amp;lt;&amp;lt; &quot;복사 생성자: &quot; &amp;lt;&amp;lt; m_pszName &amp;lt;&amp;lt; std::endl;
    }

    /**
     * @brief   Deconstructor
     */
    ~MyClass()
    {
        delete[] m_pszName;
        m_pszName = nullptr;
    }

    void Release()
    {
        delete[] m_pszName;
        m_pszName = nullptr;
    }

private:
    int m_nLength;      // 문자열 길이
    char* m_pszName;    // 문자열 데이터 (new 하는 데이터로 소멸자에서 제거 예정)
};


int main(void)
{
    MyClass cls1(&quot;Hello&quot;);              // 문자열 복사 생성자
    MyClass clsCopy = cls1;             // 복사 생성자
    MyClass clsMove = std::move(cls1);  // 복사 생성자 (이동 생성자가 없으므로)

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3L2be/btsK4gifwWy/kfCsCnIGk9NHcNZFSln2t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3L2be/btsK4gifwWy/kfCsCnIGk9NHcNZFSln2t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3L2be/btsK4gifwWy/kfCsCnIGk9NHcNZFSln2t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3L2be%2FbtsK4gifwWy%2FkfCsCnIGk9NHcNZFSln2t1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;762&quot; height=&quot;74&quot; data-origin-width=&quot;762&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/C++</category>
      <category>C++</category>
      <category>c++11</category>
      <category>Move</category>
      <category>move assignment operator</category>
      <category>move constructor</category>
      <category>std::move</category>
      <category>이동 생성자</category>
      <category>이동 할당 연산자</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/203</guid>
      <comments>https://eskeptor.tistory.com/203#entry203comment</comments>
      <pubDate>Sun, 1 Dec 2024 18:33:18 +0900</pubDate>
    </item>
    <item>
      <title>[C#, Winform] Cross Thread(UI Thread) 처리, InvokeRequired</title>
      <link>https://eskeptor.tistory.com/202</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/85bqL/btsHBAzqiyQ/JgQCuJ49xZGTyehHASCkmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/85bqL/btsHBAzqiyQ/JgQCuJ49xZGTyehHASCkmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/85bqL/btsHBAzqiyQ/JgQCuJ49xZGTyehHASCkmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F85bqL%2FbtsHBAzqiyQ%2FJgQCuJ49xZGTyehHASCkmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;C#을 사용하여 GUI를 Visual Studio를 사용하여 구성하는 방법에는 크게 &lt;code&gt;Winform(윈폼)&lt;/code&gt;과 &lt;code&gt;WPF&lt;/code&gt; 두가지가 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;WPF&lt;/code&gt;는 &lt;code&gt;Dispatcher Checker&lt;/code&gt;를 사용하여 &lt;code&gt;UI Thread가 아닌 다른 Thread를 판단&lt;/code&gt;한다면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;code&gt;Winform&lt;/code&gt;의 경우에는 &lt;code&gt;InvokeRequired&lt;/code&gt;를 사용하여 &lt;code&gt;UI Thread가 아닌 다른 Thread에서 접근하려고 하는지 판단&lt;/code&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;InvokeRequired&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;해당 Property는 &lt;code&gt;System.Windows.Forms.Control&lt;/code&gt;에 정의된 Property로, 해당 컨트롤이 &lt;code&gt;UI Thread&lt;/code&gt; 이외의 &lt;code&gt;Thread&lt;/code&gt;에서 컨트롤에 접근하려고 할 때 &lt;code&gt;Invoke&lt;/code&gt; 혹은 &lt;code&gt;BeginInvoke&lt;/code&gt;를 사용해야하는지 유무를 반환하는 Property입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;즉, &lt;code&gt;UI Thread 이외의 Thread에서 해당 컨트롤에 접근할 때 Invoke, BeginInvoke 호출을 해야한다고 알려주는 플래그&lt;/code&gt; 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;InvokeRequired를 사용하지 않고 접근할 때&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GvwfV/btsHCBqtVDt/QIMdfU6kG70xuYSKpL3r50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GvwfV/btsHCBqtVDt/QIMdfU6kG70xuYSKpL3r50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GvwfV/btsHCBqtVDt/QIMdfU6kG70xuYSKpL3r50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGvwfV%2FbtsHCBqtVDt%2FQIMdfU6kG70xuYSKpL3r50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1116&quot; height=&quot;352&quot; data-filename=&quot;1.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 스크린샷은 &lt;code&gt;TimeTaskFunc&lt;/code&gt; 라는 Task에서 수행하는 함수에서 &lt;code&gt;lblTime&lt;/code&gt; 이라는 &lt;code&gt;LabelControl&lt;/code&gt;의 속성값인 &lt;code&gt;Text&lt;/code&gt;에 접근하려고 하여 예외인 &lt;code&gt;System.InvalidOperationException&lt;/code&gt;이 발생하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;UI Thread&lt;/code&gt;가 아닌 다른 &lt;code&gt;Thread(Task)&lt;/code&gt;에서 UI 컨트롤을 접근하려고 하여 이러한 문제가 발생한 것입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;InvokeRequired를 사용하기&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YKQL4/btsHDKNCqoo/lGe9fZ07I8maJ24YmY4TQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YKQL4/btsHDKNCqoo/lGe9fZ07I8maJ24YmY4TQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YKQL4/btsHDKNCqoo/lGe9fZ07I8maJ24YmY4TQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYKQL4%2FbtsHDKNCqoo%2FlGe9fZ07I8maJ24YmY4TQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;951&quot; height=&quot;385&quot; data-filename=&quot;2.png&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;lblTime&lt;/code&gt;에 &lt;code&gt;InvokeRequired&lt;/code&gt;값을 확인하여 &lt;code&gt;BeginInvoke 또는 일반 접근&lt;/code&gt;을 하도록 변경하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드처럼 하는 경우 보다는&lt;/p&gt;
&lt;pre id=&quot;code_1716697358668&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static class ExtensionClass
{
    public static void SetText(this Control ctrl, string text)
    {
        if (ctrl.InvokeRequired)
        {
            ctrl.BeginInvoke((Action)(() =&amp;gt; ctrl.SetText(text)));
            return;
        }

        ctrl.Text = text;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 &lt;code&gt;확장 메서드 SetText&lt;/code&gt;를 만들고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTtVF4/btsHB6EBncw/73YFBZ7rFCBeBWcTjOnQb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTtVF4/btsHB6EBncw/73YFBZ7rFCBeBWcTjOnQb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTtVF4/btsHB6EBncw/73YFBZ7rFCBeBWcTjOnQb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTtVF4%2FbtsHB6EBncw%2F73YFBZ7rFCBeBWcTjOnQb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;849&quot; height=&quot;222&quot; data-filename=&quot;3.png&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 많이 사용합니다.&lt;/p&gt;</description>
      <category>Study/C#, Winform</category>
      <category>C#</category>
      <category>Invoke</category>
      <category>InvokeRequired</category>
      <category>system.invalidoperationexception</category>
      <category>WinForm</category>
      <category>윈폼</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/202</guid>
      <comments>https://eskeptor.tistory.com/202#entry202comment</comments>
      <pubDate>Sun, 26 May 2024 13:32:12 +0900</pubDate>
    </item>
    <item>
      <title>[C#] 바이트 배열 다루기 : BitConverter</title>
      <link>https://eskeptor.tistory.com/201</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QbTDl/btsro7epd5T/hq4nDel9MKmRITa1QqLm7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QbTDl/btsro7epd5T/hq4nDel9MKmRITa1QqLm7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QbTDl/btsro7epd5T/hq4nDel9MKmRITa1QqLm7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQbTDl%2Fbtsro7epd5T%2Fhq4nDel9MKmRITa1QqLm7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C#을 다루면서 비트를 다룰 때 생각보다 많이 사용하게되는 &lt;code&gt;BitConverter&lt;/code&gt;입니다.&lt;br /&gt;데이터를 바이트 배열로 변환하거나 바이트 배열을 데이터로 변환하여 전달할 때 많이 쓰입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitConverter Class&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692189226822&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//
// 요약:
//     Converts base data types to an array of bytes, and an array of bytes to base
//     data types.
public static class BitConverter&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;BitConverter&lt;/code&gt;는 &lt;code&gt;static class&lt;/code&gt;의 형태로 내부의 함수들 또한 &lt;code&gt;static 함수&lt;/code&gt;로 이루어져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitConverter에서 자주 쓰이는 함수 (데이터를 Byte 배열로 변환)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692186744044&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// bool 값을 byte[]로 변환
public static byte[] GetBytes(bool value);
    bool bValue = true;
    byte[] bytes = BitConverter.GetBytes(bValue); // 0x01

// char 값을 byte[]로 변환
public static byte[] GetBytes(char value);
    char ch = 'A';
    byte[] bytes = BitConverter.GetBytes(ch);     // 0x0041
    
// short 값을 byte[]로 변환
public static byte[] GetBytes(short value);
    short sNum = short.MaxValue;
    byte[] bytes = BitConverter.GetBytes(sNum);   // 0x7FFF

// ushort 값을 byte[]로 변환
public static byte[] GetBytes(ushort value);
    ushort usNum = ushort.MaxValue - 10;
    byte[] bytes = BitConverter.GetBytes(usNum);  // 0xFFF5

// int 값을 byte[]로 변환
public static byte[] GetBytes(int value);
    int nNum = 21883746;
    byte[] bytes = BitConverter.GetBytes(nNum);   // 0x014DEB62

// uint 값을 byte[]로 변환
public static byte[] GetBytes(uint value);
    uint unNum = 12345678;
    byte[] bytes = BitConverter.GetBytes(unNum);  // 0x00BC614E

// long 값을 byte[]로 변환
public static byte[] GetBytes(long value);
    long lNum = 6892731L;
    byte[] bytes = BitConverter.GetBytes(lNum);   // 0x0000000000692CBB

// ulong 값을 byte[]로 변환
public static byte[] GetBytes(ulong value);
    ulong ulNum = 483719208173UL;
    byte[] bytes = BitConverter.GetBytes(ulNum);  // 0x000000709FE95CED

// float 값을 byte[]로 변환
public static byte[] GetBytes(float value);
    float fNum = 123.456f;
    byte[] bytes = BitConverter.GetBytes(fNum);   // 0x42F6E979

// double 값을 byte[]로 변환
public static byte[] GetBytes(double value);
    double dNum = 3.141592;
    byte[] bytes = BitConverter.GetBytes(dNum);   // 0x400921FAFc8B007A&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitConverter &lt;b&gt;에서 자주 쓰이는 함수 (Byte 배열을 자료형 데이터 변환)&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1692189421860&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// byte[]를 bool형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static bool ToBoolean(byte[] value, int startIndex);
    bool bValue = BitConverter.ToBoolean(bytes, 0);

// byte[]를 char형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static char ToChar(byte[] value, int startIndex);
    char ch = BitConverter.ToChar(bytes, 0);

// byte[]를 short형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static short ToInt16(byte[] value, int startIndex);
    short sNum = BitConverter.ToInt16(bytes, 0);

// byte[]를 ushort형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static ushort ToUInt16(byte[] value, int startIndex);
    ushort usNum = BitConverter.ToUInt16(bytes, 0);

// byte[]를 int형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static int ToInt32(byte[] value, int startIndex);
    int nNum = BitConverter.ToInt32(bytes, 0);

// byte[]를 uint형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static uint ToUInt32(byte[] value, int startIndex);
    uint unNum = BitConverter.ToUInt32(bytes, 0);

// byte[]를 long형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static long ToInt64(byte[] value, int startIndex);
    long lNum = BitConverter.ToInt64(bytes, 0);

// byte[]를 ulong형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static ulong ToUInt64(byte[] value, int startIndex);
    ulong lNum = BitConverter.ToUInt64(bytes, 0);

// byte[]를 float형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static float ToSingle(byte[] value, int startIndex);
    float fNum = BitConverter.ToSingle(bytes, 0);

// byte[]를 double형 데이터로 (startIndex는 value의 변환 시작 인덱스)
public static double ToDouble(byte[] value, int startIndex);
    double dNum = BitConverter.ToDouble(bytes, 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Big Endian과 Little Endian&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbCZLW/btsrqwdXIdw/zSTx8zXnsuWODjXpd2oaU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbCZLW/btsrqwdXIdw/zSTx8zXnsuWODjXpd2oaU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbCZLW/btsrqwdXIdw/zSTx8zXnsuWODjXpd2oaU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbCZLW%2FbtsrqwdXIdw%2FzSTx8zXnsuWODjXpd2oaU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;561&quot; height=&quot;500&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Big Endian과 Little Endian은 위와 같다는 것을 우리는 알고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 현재 프로그램을 구동하고 있는 PC의 Endian 형태는 어떻게 알 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;BitConverter&lt;/code&gt;는 &lt;code&gt;IsLittleEndian&lt;/code&gt; 이라는 필드를 제공하고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1692187502536&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// This field indicates the &quot;endianess&quot; of the architecture.
// The value is set to true if the architecture is
// little endian; false if it is big endian.
#if BIGENDIAN
[Intrinsic]
public static readonly bool IsLittleEndian /* = false */;
#else
[Intrinsic]
public static readonly bool IsLittleEndian = true;
#endif&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 Visual Studio를 실행하는 대다수의 컴퓨터는 LittleEndian 임으로 &lt;code&gt;true&lt;/code&gt;를 반환 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;예제&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bikRDW/btsrrZUb26u/DpSlD9zKf40sbmRkiptUVk/BitConvert_Example.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;BitConvert_Example.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.06MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Study/C#, Winform</category>
      <category>bitconverter</category>
      <category>C#</category>
      <category>getBytes</category>
      <category>바이트배열</category>
      <category>변환</category>
      <category>비트컨버터</category>
      <category>형변환</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/201</guid>
      <comments>https://eskeptor.tistory.com/201#entry201comment</comments>
      <pubDate>Wed, 16 Aug 2023 21:48:08 +0900</pubDate>
    </item>
    <item>
      <title>[리뷰] HP Victus 16 단점 위주 리뷰 (빅터스 16)</title>
      <link>https://eskeptor.tistory.com/200</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;IMG_20230723_175613223.jpg&quot; data-origin-width=&quot;3072&quot; data-origin-height=&quot;4096&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKVuD6/btsoyrUEFA0/MwvKDGHLtPDKpOu67tjjx0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKVuD6/btsoyrUEFA0/MwvKDGHLtPDKpOu67tjjx0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKVuD6/btsoyrUEFA0/MwvKDGHLtPDKpOu67tjjx0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKVuD6%2FbtsoyrUEFA0%2FMwvKDGHLtPDKpOu67tjjx0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3072&quot; height=&quot;4096&quot; data-filename=&quot;IMG_20230723_175613223.jpg&quot; data-origin-width=&quot;3072&quot; data-origin-height=&quot;4096&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-07-23 182717.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;117&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbStrV/btsoyJnAQt6/bvjTeYGDAEVFrki6SfjeZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbStrV/btsoyJnAQt6/bvjTeYGDAEVFrki6SfjeZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbStrV/btsoyJnAQt6/bvjTeYGDAEVFrki6SfjeZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbStrV%2FbtsoyJnAQt6%2FbvjTeYGDAEVFrki6SfjeZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;816&quot; height=&quot;117&quot; data-filename=&quot;화면 캡처 2023-07-23 182717.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;117&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HP사의 보급형 게이밍 노트북 브랜드인 빅터스시리즈의 노트북을 사게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(HP에는 두 가지 게이밍 브랜드가 존재하죠. Omen(오멘)과 Victus(빅터스))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 나온지 꽤 된 노트북이라 많은 리뷰가 있을 것이니 저는 약 4일간 사용했을 때 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점을 위주로 리뷰&lt;/b&gt;&lt;/span&gt;를 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(좋은 리뷰는 많이들 하신 것 같으니)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 빅터스 16의 d모델 기준입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-07-23 183408.png&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btTrPB/btsoyVuqu1h/kQJnNkE78eZvI0xn0X1MY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btTrPB/btsoyVuqu1h/kQJnNkE78eZvI0xn0X1MY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btTrPB/btsoyVuqu1h/kQJnNkE78eZvI0xn0X1MY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtTrPB%2FbtsoyVuqu1h%2FkQJnNkE78eZvI0xn0X1MY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;978&quot; height=&quot;198&quot; data-filename=&quot;화면 캡처 2023-07-23 183408.png&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(저는 Victus 16-d1121TX모델이지만 HP 에서는 16-d 모델 전체를 하나로 보고 있기 때문입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 윈도우 10 설치 힘듬&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-23 183616.png&quot; data-origin-width=&quot;963&quot; data-origin-height=&quot;581&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZDOC0/btsoyWUpKN6/yu2ovkXOayxPb8y0d3bvn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZDOC0/btsoyWUpKN6/yu2ovkXOayxPb8y0d3bvn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZDOC0/btsoyWUpKN6/yu2ovkXOayxPb8y0d3bvn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZDOC0%2FbtsoyWUpKN6%2Fyu2ovkXOayxPb8y0d3bvn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;963&quot; height=&quot;581&quot; data-filename=&quot;스크린샷 2023-07-23 183616.png&quot; data-origin-width=&quot;963&quot; data-origin-height=&quot;581&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빅터스 16은 기본적으로 윈도우 11 지원으로 제품을 냈습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 윈도우 10의 드라이버를 공식적으로 지원해주지 않는데 윈도우 자체의 드라이버 업데이트 기능으로 될 것 같아서 설치해보았으나 칩셋과 무선랜 드라이버가 잡히지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU도 인텔 12세대임으로 윈도우 11을 까는게 맞습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아마 까는 방법이 있긴 할 겁니다.... 하지만 그냥 윈도우 11을 까는게 더 나을수도)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 초기형 모델인 경우는 A/S 받아야 될 수도 있음&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빅터스 16에는 M.2가 2개 제공됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 기본 제공해주는 SSD가 꽂힌 첫 번재 슬롯이 아닌 확장형 두 번째 슬롯이 문제인데 제가 받은 모델은 그러하지 않았지만 초기형 모델의 경우 M.2 두 번째 슬롯과 그래픽 카드가 충돌한다는 문제가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-07-23 184047.png&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;756&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3xlbk/btsozkgOZHe/Vi6Ivwi0vuv7bblbdLvdpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3xlbk/btsozkgOZHe/Vi6Ivwi0vuv7bblbdLvdpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3xlbk/btsozkgOZHe/Vi6Ivwi0vuv7bblbdLvdpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3xlbk%2FbtsozkgOZHe%2FVi6Ivwi0vuv7bblbdLvdpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1022&quot; height=&quot;756&quot; data-filename=&quot;스크린샷 2023-07-23 184047.png&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;756&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 HP 코리아에서 인식하고 있는 문제로 빅터스 16을 사신 분은 꼭 확장형 슬롯에 SSD를 끼어서 문제가 있는지 없는지 확인해 보셔야 할 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1690105475537&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;HP Victus 16-d1111tx (또는 빅터스 제품군) 구매자 분들께 올리는 글&quot; data-og-description=&quot;안녕하세요. 요번 빅스마일데이때 노트북 5대를 추가로 질렀는데... 긴히 알려드려야 할 것 같아 간만에&quot; data-og-host=&quot;m.ppomppu.co.kr&quot; data-og-source-url=&quot;https://m.ppomppu.co.kr/new/bbs_view.php?id=computer&amp;amp;no=663329&quot; data-og-url=&quot;http://m.ppomppu.co.kr/new/bbs_view.php?id=computer&amp;amp;no=663329&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ct8Ir9/hyTo1xwFR3/GEf2ryZb5A53zHzmoCCuPK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://m.ppomppu.co.kr/new/bbs_view.php?id=computer&amp;amp;no=663329&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://m.ppomppu.co.kr/new/bbs_view.php?id=computer&amp;amp;no=663329&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ct8Ir9/hyTo1xwFR3/GEf2ryZb5A53zHzmoCCuPK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;HP Victus 16-d1111tx (또는 빅터스 제품군) 구매자 분들께 올리는 글&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요. 요번 빅스마일데이때 노트북 5대를 추가로 질렀는데... 긴히 알려드려야 할 것 같아 간만에&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;m.ppomppu.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이미 이 문제를 알고 사서 대비하고 있었는데 제가 산 제품은 문제가 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 스피커에서 딱 딱 소리가 남&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1690105577834&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;HP 16.1인치 게이밍 노트북 PC Victus 16-d1000 RCTO 기본 모델 소프트웨어 및 드라이버 다운로드 | HP&amp;reg; 고&quot; data-og-description=&quot;저는 HP Virtual Agent입니다. 찾고 있는 것이 무엇인지 알려주시면 해결책을 찾을 수 있도록 지원해 드리겠습니다.&quot; data-og-host=&quot;support.hp.com&quot; data-og-source-url=&quot;https://support.hp.com/kr-ko/drivers/selfservice/victus-by-hp-16.1-inch-gaming-laptop-pc-16-d1000/2101036104/model/2101036106&quot; data-og-url=&quot;https://support.hp.com/kr-ko/drivers/selfservice/victus-by-hp-16.1-inch-gaming-laptop-pc-16-d1000/2101036104/model/2101036106&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cl6E4l/hyTo2QJWKF/4Rn1bt20Q1jGATdxOvG1Ek/img.png?width=738&amp;amp;height=690&amp;amp;face=0_0_738_690&quot;&gt;&lt;a href=&quot;https://support.hp.com/kr-ko/drivers/selfservice/victus-by-hp-16.1-inch-gaming-laptop-pc-16-d1000/2101036104/model/2101036106&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://support.hp.com/kr-ko/drivers/selfservice/victus-by-hp-16.1-inch-gaming-laptop-pc-16-d1000/2101036104/model/2101036106&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cl6E4l/hyTo2QJWKF/4Rn1bt20Q1jGATdxOvG1Ek/img.png?width=738&amp;amp;height=690&amp;amp;face=0_0_738_690');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;HP 16.1인치 게이밍 노트북 PC Victus 16-d1000 RCTO 기본 모델 소프트웨어 및 드라이버 다운로드 | HP&amp;reg; 고&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;저는 HP Virtual Agent입니다. 찾고 있는 것이 무엇인지 알려주시면 해결책을 찾을 수 있도록 지원해 드리겠습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;support.hp.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 사이트는 HP 공식 다운로드 센터 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 사이트에서 사운드 드라이버를 설치하고 나면 불규칙적으로 딱 딱 소리가 나게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(딱 딱 소리는 뭔가 튀는 듯한 소리입니다. 뭔가를 재생중이거나 재생중이지 않아도 납니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 타 노트북에서 경험해 본 문제라서 저는 해결을 했지만 처음 겪으신 분들은 A/S를 요청하실수도 있을 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이 문제는 타 노트북 또는 데스크탑에서도 일어나는 문제입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단히 말씀드리자면 윈도우10 (11 포함)에서 나타나던 사운드 드라이버 충돌 관련 문제였던 걸로 기억합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 수행한 해결 방법은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 먼저 HP 공식 다운로드 센터에서 HP 드라이버를 다운로드 후 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 딱딱 소리가 난다면 3번 부터 계속 진행, 딱딱 소리가 안나면 여기서 끝&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;413&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwXPog/btsoIN3aDyi/wna8iykkgp1Oh7wCQ1hWEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwXPog/btsoIN3aDyi/wna8iykkgp1Oh7wCQ1hWEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwXPog/btsoIN3aDyi/wna8iykkgp1Oh7wCQ1hWEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwXPog%2FbtsoIN3aDyi%2Fwna8iykkgp1Oh7wCQ1hWEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;846&quot; height=&quot;413&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;413&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) &lt;code&gt;윈도우 설정&lt;/code&gt;에서 &lt;code&gt;시스템 - 소리 - 모든 사운드 장치 - 속성&lt;/code&gt; 에서 &lt;code&gt;스테레오 믹스 항목&lt;/code&gt;을 &lt;code&gt;허용 함&lt;/code&gt;을 누른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;(허용함 상태가 되면 버튼은 &quot;허용 안 함&quot;이 됨)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cf87Al/btsoxX7o9Nz/gJUuUhIGvxF5EKkVjAxNX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cf87Al/btsoxX7o9Nz/gJUuUhIGvxF5EKkVjAxNX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cf87Al/btsoxX7o9Nz/gJUuUhIGvxF5EKkVjAxNX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcf87Al%2FbtsoxX7o9Nz%2FgJUuUhIGvxF5EKkVjAxNX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;839&quot; height=&quot;336&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;839&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) &lt;code&gt;윈도우 설정&lt;/code&gt;에서 &lt;code&gt;시스템 - 소리&lt;/code&gt; 에서 &lt;code&gt;말하기 또는 녹음 장치 선택&lt;/code&gt;의 항목을 &lt;code&gt;스테레오 믹스&lt;/code&gt;로 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 이 상태에서 &lt;code&gt;윈도우 업데이트&lt;/code&gt;를 다시 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 윈도우 업데이트를 하면서 아마 리얼텍 관련 오디오 드라이버가 새로 설치하게 될텐데 설치하고 나면 스테레오 믹스는 다시 비활성화 되며 기본 설정이 마이크 배열로 변경 될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 만약 자동 업데이트가 없다면 이 상태에서 공식 드라이버를 다시 설치해 보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 이도저도 안되신다면 A/S 받으세요. 불규칙적으로 자주 일어나서 현상이 쉽게 발현되니 A/S센터에서 바로 인지 할겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 이 과정을 거치면 딱 딱 소리는 대부분 사라지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 모니터 힌지 덜렁거림&lt;/b&gt;&lt;/h2&gt;

            &lt;figure class=&quot;unsupported component-kakaotv&quot; contenteditable=&quot;false&quot; style=&quot;background:#000;margin:16px 0;min-height:72px;padding:10px 16px;display:flex;align-items:center;justify-content:center;text-align:center;box-sizing:border-box;width:100%;max-width:100%;&quot;&gt;
                &lt;p contenteditable=&quot;false&quot; style=&quot;margin:0;color:#8a8a8a;font-size:13px;line-height:1.6;user-select:none;pointer-events:none;&quot;&gt;동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.&lt;/p&gt;
            &lt;/figure&gt;
        
&lt;p data-ke-size=&quot;size16&quot;&gt;보시면 압니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덜렁 거립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바닥이 단단하게 고정된 곳이 아니라면 (예를 들어 침대 위) 흔들 흔들 할겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마치며&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A/S는 HP이기에 삼성, LG는 아니더라도 타사 대비 어렵지 않습니다.&lt;/li&gt;
&lt;li&gt;무게는 어댑터를 포함하면 약 3KG에 가까워지는데 이 정도의 게이밍 노트북에서는 그래도 흔한 경우이기에 단점으로 보지는 않았습니다.&lt;/li&gt;
&lt;li&gt;소음은 평소 간단한 작업(웹, 영상)에는 거의 나지 않으며 무거운 작업(컴파일, 게임)시에는 비행기가 이륙합니다.&lt;br /&gt;(Omen Gaming Hub에서 성능 제어를 저소음으로 하면 그래도 낫지만 조용한 환경에서는 비추입니다.)&lt;br /&gt;하지만 이정도 소음은 게이밍 노트북에서는 흔하기 때문에 단점으로 크게 지적하지는 않았습니다.&lt;/li&gt;
&lt;li&gt;파스 점수나 시네벤치는 이미 여기저기 나와있기에 따로 추가하지 않았습니다.&lt;/li&gt;
&lt;li&gt;이 노트북은 200W 어댑터를 제공합니다.&lt;br /&gt;현재 200W 충전을 지원하는 PD충전기가 없기에 PD충전은 지원하지 않습니다.&lt;br /&gt;(하지만 저는 이게 단점이라고 보기가.......단점인가...?)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 특가로 약 85만원에 구입하였으나 정가인 110만원이었더라도 괜찮았을 것 같지만 그 가격이었다면 안샀....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(110만원 근처라면 대안이 좀 많아지는....)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제가 보기에 가장 큰 단점은 힌지가 덜렁 덜렁....&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(아마 다음 세대에서는 나아지지 않을까 싶네요...)&lt;/p&gt;</description>
      <category>Computer/Hardware</category>
      <category>16-d1121TX</category>
      <category>HP</category>
      <category>victus 16</category>
      <category>게이밍노트북</category>
      <category>단점 리뷰</category>
      <category>빅터스 16</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/200</guid>
      <comments>https://eskeptor.tistory.com/200#entry200comment</comments>
      <pubDate>Sun, 23 Jul 2023 19:27:02 +0900</pubDate>
    </item>
    <item>
      <title>[C#] 바이트 배열을 이용한 비트 다루기 : BitArray</title>
      <link>https://eskeptor.tistory.com/199</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgAxil/btsnGYSJppc/DgzgfZIH8iKKQ8bwyobDZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgAxil/btsnGYSJppc/DgzgfZIH8iKKQ8bwyobDZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgAxil/btsnGYSJppc/DgzgfZIH8iKKQ8bwyobDZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgAxil%2FbtsnGYSJppc%2FDgzgfZIH8iKKQ8bwyobDZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1920&quot; height=&quot;1080&quot; data-filename=&quot;블로그_메인이미지_폼.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;C#을 다루면서 비트를 다룰 때 생각보다 많이 사용하게되는 &lt;code&gt;BitArray&lt;/code&gt;입니다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;바이트 배열을 넣어서 사용하기도 하고 비트의 개수를 넣어서 사용하기도 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;BitArray 생성자&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689426875857&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using System.Collections;    // BitArray를 사용하기 위함

// length 만큼의 길이를 가진 비트배열을 만듬 (모든 비트는 0)
public BitArray(int length);

// length 만큼의 길이를 가진 비트배열을 만들고 기본값을 defaultValue로 설정
public BitArray(int length, bool defaultValue)

// 바이트 배열을 비트배열로 만듬
// 예) bytes = byte[2] -&amp;gt; BitArray를 16칸 자리를 만듬
//     (BitArray[0~7] = bytes[0], BitArray[8~15] = bytes[1])
public BitArray(byte[] bytes)

// Boolean 값을 토대로 비트배열을 만듬
// 예) { false, false, true, false }을 넣으면 4비트짜리 배열을 만듬 (0100)
public unsafe BitArray(bool[] values)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BitArray는 위의 생성자를 주로 사용하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 생성자에서 보면 BitArray는 비트 표현을 boolean으로 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0은 false, 1은 true로 표현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - Set(Int32, Boolean)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689427387318&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// index 위치의 비트를 value로 설정
public void Set(int index, bool value)

// 예시
BitArray bitArray = new BitArray(8);  // 00000000 = 0
bitArray.Set(2, true);                // 00000100 = 4&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - Get(Int32)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689427702376&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// index 위치의 비트 값을 bool값으로 반환
public bool Get(int index)

// 예시
BitArray bitArray1 = new BitArray(new bool[] {true, false, true, false}); // 0101 = 5
bool bBit3 = bitArray1.Get(2);  // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - And(BitArray)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689427813415&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// value와 And 연산을 수행한 결과를 반환
// 단, value와 BitArray 길이는 같아야함(같지 않으면 ArgumentException)
public unsafe BitArray And(BitArray value)

// 예시
BitArray bitArray1 = new BitArray(new byte[] {21}); // 00010101
BitArray bitArray2 = new BitArray(8, true);         // 11111111
BitArray bitArrayAND = bitArray1.And(bitArray2);    // 00010101&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - Or(BitArray)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689428181682&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// value와 Or 연산을 수행한 결과를 반환
// 단, value와 BitArray 길이는 같아야함(같지 않으면 ArgumentException)
public unsafe BitArray Or(BitArray value)

// 예시
BitArray bitArray1 = new BitArray(new byte[] {21}); // 00010101
BitArray bitArray2 = new BitArray(8, true);         // 11111111
BitArray bitArrayOR = bitArray1.Or(bitArray2);      // 11111111&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - Xor(BitArray)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689428463821&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// value와 XOR 연산을 수행한 결과를 반환
// 단, value와 BitArray 길이는 같아야함(같지 않으면 ArgumentException)
public unsafe BitArray Xor(BitArray value)

// 예시
BitArray bitArray1 = new BitArray(new byte[] {21}); // 00010101
BitArray bitArray2 = new BitArray(8, true);         // 11111111
BitArray bitArrayXOR = bitArray1.Xor(bitArray2);    // 11101010&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - Not()&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689428555744&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 반전(NOT)을 수행한 결과를 반환
public unsafe BitArray Not()

// 예시
BitArray bitArray = new BitArray(new byte[] {21}); // 00010101
BitArray bitArrayNOT = bitArray.Not();             // 11101010&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - RightShift(Int32)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689428738033&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 오른쪽으로 count만큼 시프트한 결과를 반환
public BitArray RightShift(int count)

// 예시
BitArray bitArray = new BitArray(new byte[] {21}); // 00010101
BitArray bitArrayRS = bitArray.RightShift(4);      // 00000001&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - LeftShift(Int32)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689428782065&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 왼쪽으로 count만큼 시프트한 결과를 반환
public BitArray LeftShift(int count)

// 예시
BitArray bitArray = new BitArray(new byte[] {21}); // 00010101
BitArray bitArrayLS = bitArray.LeftShift(4);       // 01010000&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 메소드 - CopyTo(Array, Int32)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1689429035387&quot; class=&quot;csharp&quot; data-ke-language=&quot;csharp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// BitArray의 값을 array의 index 위치에 복사
// BitArray의 값을 byte 배열로 변환하는데 많이 사용함
public unsafe void CopyTo(Array array, int index)

// 예시
BitArray bitArray = new BitArray(new byte[] {21}); // 00010101
BitArray bitArrayLS = bitArray.LeftShift(4);       // 01010000

int nByteArr = bitArrayLS.Count / 8 + bitArrayLS.Count % 8; // 비트 길이 계산
byte[] bytes = new byte[nByteArr];   // bytes = new byte[1];
bitArrayLS.CopyTo(bytes, 0);         // bytes[0] = 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;BitArray 속성 - Count와 Length&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3hCXk/btsnGkobk0b/CRUzJW86a4IzSZs9K3RjA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3hCXk/btsnGkobk0b/CRUzJW86a4IzSZs9K3RjA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3hCXk/btsnGkobk0b/CRUzJW86a4IzSZs9K3RjA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3hCXk%2FbtsnGkobk0b%2FCRUzJW86a4IzSZs9K3RjA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;344&quot; height=&quot;148&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;344&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;BitArray&lt;/code&gt;에는 &lt;code&gt;Count&lt;/code&gt;와 &lt;code&gt;Length&lt;/code&gt;라는 속성이 있는데 둘은 같은 &lt;code&gt;BitArray의 길이라는 값을 반환&lt;/code&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신 &lt;code&gt;Count는 Get&lt;/code&gt;만 할 수 있고 &lt;code&gt;Length는 Get, Set&lt;/code&gt; 둘 다 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/C#, Winform</category>
      <category>bit to byte</category>
      <category>BitArray</category>
      <category>bitarray to byte</category>
      <category>C#</category>
      <category>바이트</category>
      <category>비트배열</category>
      <category>비트어레이</category>
      <category>비트연산</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/199</guid>
      <comments>https://eskeptor.tistory.com/199#entry199comment</comments>
      <pubDate>Sat, 15 Jul 2023 22:57:03 +0900</pubDate>
    </item>
    <item>
      <title>[C++/Console] 테트리스 만들어 보기 - 7 (자동 하강, 블럭 회전, 라인 클리어)</title>
      <link>https://eskeptor.tistory.com/198</link>
      <description>&lt;figure id=&quot;og_1681724004434&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[C++/Console] 테트리스 만들어 보기 - 6 (바닥 충돌, 블럭 랜덤 생성)&quot; data-og-description=&quot;[C++/Console] 테트리스 만들어 보기 - 5 (충돌 판정 - 벽, 블럭) [C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임) [C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) [C++/Console] &quot; data-og-host=&quot;eskeptor.tistory.com&quot; data-og-source-url=&quot;https://eskeptor.tistory.com/196&quot; data-og-url=&quot;https://eskeptor.tistory.com/196&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3nC21/hySiZ8SbZf/MkxbC4cDqyVoDP8HltIb0k/img.gif?width=234&amp;amp;height=499&amp;amp;face=0_0_234_499,https://scrap.kakaocdn.net/dn/btyNls/hySi8Y3ofA/CszYx7O3yG4ylVAG0U9ack/img.gif?width=234&amp;amp;height=499&amp;amp;face=0_0_234_499&quot;&gt;&lt;a href=&quot;https://eskeptor.tistory.com/196&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://eskeptor.tistory.com/196&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3nC21/hySiZ8SbZf/MkxbC4cDqyVoDP8HltIb0k/img.gif?width=234&amp;amp;height=499&amp;amp;face=0_0_234_499,https://scrap.kakaocdn.net/dn/btyNls/hySi8Y3ofA/CszYx7O3yG4ylVAG0U9ack/img.gif?width=234&amp;amp;height=499&amp;amp;face=0_0_234_499');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 6 (바닥 충돌, 블럭 랜덤 생성)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 5 (충돌 판정 - 벽, 블럭) [C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임) [C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) [C++/Console]&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eskeptor.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에는 바닥 충돌, 블럭 랜덤 생성에 대해서 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 시간이 지남에 따라 자동으로 블럭이 하강하고, 스페이스바를 눌렀을 때 블럭이 회전되며, 하나의 라인을 형성하면 해당 라인을 클리어 후 점수가 올라가는 점수 시스템에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;자동 하강&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테트리스는 지정된 시간이 지나면 블럭이 아래로 하강하는 시스템을 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 구현하기 위해서는 &lt;code&gt;clock 함수&lt;/code&gt;를 사용하여야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681724674949&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;ctime&amp;gt;      // 또는 #include &amp;lt;time.h&amp;gt;

clock_t clock(void);  // 현재 시간을 반환
// clock_t는 실제로 long형&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 &lt;code&gt;clock 함수&lt;/code&gt;는 실제로는 엄청 정밀하지는 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 본인이 다른 프로젝트에서 정말 정밀하게 시간을 제어해야 한다면 &lt;code&gt;QueryPerformanceCounter 함수&lt;/code&gt;를 사용하셔야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이 테트리스 프로젝트에서는 엄청 정밀하게 하지 않아도 되어 &lt;code&gt;clock 함수&lt;/code&gt;를 사용합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;code&gt;clock 함수&lt;/code&gt;를 이용하여 마지막으로 방향키가 움직였을 때를 기준으로 1000ms를 카운트하여 아래로 한 칸씩 내려오도록 할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681724948772&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Console Structure
struct stConsole
{
    // 생략 ..

    // Clock
    clock_t timeStart;  // 마지막 입력지점의 시간

    stConsole()
        : hConsole(nullptr), hBuffer{ nullptr, }, nCurBuffer(0)
        , rdGen(rdDevice()), rdBlockDist(0, 6), rdDirDist(CPlayer::eDirection::Dir0, CPlayer::eDirection::Dir270)
        , timeStart(clock())
    {}
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;stConsole 구조체&lt;/code&gt;에 &lt;code&gt;timeStart 변수&lt;/code&gt;를 하나 선언합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 &lt;code&gt;clock_t&lt;/code&gt;는 &lt;code&gt;ctime&lt;/code&gt; 혹은 &lt;code&gt;time.h&lt;/code&gt; 헤더를 포함해야 하나 &lt;code&gt;&amp;lt;random&amp;gt;&lt;/code&gt;을 포함하면 같이 포함됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681725579014&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InputKey()
{
    int nKey = 0;

    if (_kbhit() &amp;gt; 0)
    {
        nKey = _getch();

        switch (nKey)
        {
            // 생략 ...
            case eKeyCode::KEY_DOWN:
            {
                if (IsMoveAvailable(0, 1))
                {
                    g_player.AddPosition(0, 1);
                    g_console.timeStart = clock();   // &amp;lt;-- 키 입력 기준 시간 저장
                }
                break;
            }
            // 생략 ...
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;InputKey 함수&lt;/code&gt;의 &lt;code&gt;KEY_DOWN&lt;/code&gt; 케이스에서 아래쪽으로 움직일 수 있을 때 시간을 저장하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681725814616&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CheckBottom()
{
    // 마지막 입력 시간에서 현재 시간을 뺌 = 진행된 시간(ms)
    clock_t ctTimeDiff = clock() - g_console.timeStart;
    
    // 1000ms가 지나지 않았다면 바로 return
    if (ctTimeDiff &amp;lt; 1000)
        return;

    // 1000ms 가 지났으니 현재 시간을 다시 저장
    g_console.timeStart = clock();

    if (IsMoveAvailable(0, 1))
    {
        // 아래로 한 칸 이동
        g_player.AddPosition(0, 1);
        return;
    }

    memcpy_s(g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);

    g_player.SetPosition(START_POS_X, START_POS_Y);
    g_player.SetBlock(RandomBlock());
    g_player.SetDirection((CPlayer::eDirection)RamdomDirection());

    g_prevPlayerData = g_player;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;CheckBottom 함수&lt;/code&gt;에 시간을 계산하여 해당 시간이 1000ms가 넘었을 때 자동으로 한 칸 내려오도록 함수를 변경합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 수정 후 테트리스를 실행해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vxXlw/btsaKxgslZ2/mpInqmIMcDPVaJkjwLUea0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vxXlw/btsaKxgslZ2/mpInqmIMcDPVaJkjwLUea0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vxXlw/btsaKxgslZ2/mpInqmIMcDPVaJkjwLUea0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/vxXlw/btsaKxgslZ2/mpInqmIMcDPVaJkjwLUea0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;276&quot; height=&quot;521&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 시간이 지났을 때 자동으로 아래로 한 칸씩 내려오는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 임의로 한 칸을 움직였을 때도 키 입력이 끝난 이후로 일정시간 이후 다시 한 칸씩 내려오는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;블럭 회전 (스페이스 바 입력 시)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 스페이스 바를 눌렀을 때 블럭이 회전하도록 하여봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 블럭이 회전이 가능한 지 확인하는 함수를 먼저 만들어봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1681725863002&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool IsRotateAvailable()
{
    // 현재 블럭을 다음 방향으로 돌렸을 때의 블럭 모양
    int* pBlock = GetRotateBlock(g_player.GetBlock(), g_player.GetNextDirection());

    // 돌린 블럭이 벽에 부딛히지 않는지 확인
    return !IsCollision(pBlock, g_player.GetCursor());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;InputKey 함수&lt;/code&gt;에 블럭 회전 기능을 넣어 봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1681725958365&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InputKey()
{
    int nKey = 0;

    if (_kbhit() &amp;gt; 0)
    {
        nKey = _getch();

        switch (nKey)
        {
            // 생략 ...
            case eKeyCode::KEY_SPACE:
            {
                // 블럭 회전이 가능한 경우
                if (IsRotateAvailable())
                    // 블럭을 회전 시킴
                    g_player.SetNextDirection();
                break;
            }
            // 생략 ...
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실행하여봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blWwPN/btsaSSxbOVr/CB6FeicfcpOnhspqdVsnn0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blWwPN/btsaSSxbOVr/CB6FeicfcpOnhspqdVsnn0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blWwPN/btsaSSxbOVr/CB6FeicfcpOnhspqdVsnn0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/blWwPN/btsaSSxbOVr/CB6FeicfcpOnhspqdVsnn0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;276&quot; height=&quot;521&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;라인 클리어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라인 클리어의 경우에 실제로 한 줄이 되는 라인을 지우는 것이 아닌 해당 줄의 정보를 바로 윗줄의 정보로 덮어쓰기 하는 방식으로 진행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.jpg&quot; data-origin-width=&quot;1287&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blQYJv/btsaTfeNfxC/TTIO9nDpKMO8k5kThIHAvK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blQYJv/btsaTfeNfxC/TTIO9nDpKMO8k5kThIHAvK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blQYJv/btsaTfeNfxC/TTIO9nDpKMO8k5kThIHAvK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblQYJv%2FbtsaTfeNfxC%2FTTIO9nDpKMO8k5kThIHAvK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1287&quot; height=&quot;412&quot; data-filename=&quot;1.jpg&quot; data-origin-width=&quot;1287&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 그림처럼 라인이 채워진 부분을 기준으로 위에서 한 칸씩 덮어써지는 느낌으로 구현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라인 클리어 확인 시점을 블럭이 바닥에 닿아서 다음 블럭으로 넘어가기 전에 테트리스 맵 배열을 탐색하여 라인이 이루어졌는지 확인하도록 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1681726846322&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool CheckFillLine()
{
    // 현재 플레이어(블럭)의 좌표
    COORD curPos = g_player.GetCursor();
    // 라인 클리어를 해야하는지 유무
    bool bFill = true;
    // 라인 클리어를 시킬 배열의 사이즈
    int nSize = 0;
    // 라인 클리어를 해야하는지 유무
    bool bLineCleared = false;

    // 한 블럭은 4x4의 크기임으로 Y좌표로 +4까지만 확인
    for (int nY = curPos.Y; nY &amp;lt; curPos.Y + 4; ++nY)
    {
        bFill = true;

        for (int nX = 1; nX &amp;lt; MAP_WIDTH; ++nX)
        {
            //  현재 라인에서 빈 칸이 있다면 해당 라인은 클리어될 수 없음
            if (g_nArrMapBackup[nY][nX] == 0)
            {
                bFill = false;
                break;
            }
        }

        // 라인 클리어를 해야 한다면
        if (bFill &amp;amp;&amp;amp;
            nY &amp;lt; MAP_HEIGHT - 1)
        {
            nSize = sizeof(int) * MAP_WIDTH * (nY - 1);
            // 이전의 라인 정보를 다음 라인 정보에 옮김 (즉, 현재 라인이 지워지고 윗 라인이 아래로 내려오는 효과)
            memcpy_s(g_nArrMapBackup[2], nSize, g_nArrMapBackup[1], nSize);
            bLineCleared = true;
        }
    }

    return bLineCleared;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 라인 클리어를 하는 함수를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681727759786&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CheckBottom()
{
    // 마지막 입력 시간에서 현재 시간을 뺌 = 진행된 시간(ms)
    clock_t ctTimeDiff = clock() - g_console.timeStart;

    // 1000ms가 지나지 않았다면 바로 return
    if (ctTimeDiff &amp;lt; 1000)
        return;

    // 1000ms 가 지났으니 현재 시간을 다시 저장
    g_console.timeStart = clock();

    if (IsMoveAvailable(0, 1))
    {
        // Y Move
        g_player.AddPosition(0, 1);
        return;
    }

    memcpy_s(g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);

    // 라인 클리어 기능 추가
    if (CheckFillLine())
    {
        g_player.AddGameScore(1);
        memcpy_s(g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);
    }

    g_player.SetPosition(START_POS_X, START_POS_Y);
    g_player.SetBlock(RandomBlock());
    g_player.SetDirection((CPlayer::eDirection)RamdomDirection());

    g_prevPlayerData = g_player;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 CheckBottom 함수에 라인 클리어 기능을 넣습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실행해봅니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.gif&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;521&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qeUE8/btsaETkfE1W/9kSbIKSmiLq4rJYzIMcook/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qeUE8/btsaETkfE1W/9kSbIKSmiLq4rJYzIMcook/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qeUE8/btsaETkfE1W/9kSbIKSmiLq4rJYzIMcook/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/qeUE8/btsaETkfE1W/9kSbIKSmiLq4rJYzIMcook/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;276&quot; height=&quot;521&quot; data-filename=&quot;3.gif&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;521&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 라인 클리어까지 잘 되는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간이 아마 마지막이 될 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 게임 오버, 재시작, 점수화면 표시에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현재 까지의 진행 프로젝트 다운로드&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/wFO9w/btsaRZRbAmg/kZv7qozvkfpAbr5Yw51rSk/TetrisCpp_7%ED%8E%B8.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;TetrisCpp_7편.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Study/C++</category>
      <category>C++</category>
      <category>clock</category>
      <category>Tetris</category>
      <category>TIME</category>
      <category>라인 클리어</category>
      <category>블럭 회전</category>
      <category>자동 하강</category>
      <category>테트리스</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/198</guid>
      <comments>https://eskeptor.tistory.com/198#entry198comment</comments>
      <pubDate>Mon, 17 Apr 2023 19:54:27 +0900</pubDate>
    </item>
    <item>
      <title>[C++11] unordered_map</title>
      <link>https://eskeptor.tistory.com/197</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근에 스크립트형 언어 컴파일러를 만들고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(실시간 스크립트 변형 후 동작을 위한)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정 중에서 &lt;b&gt;어휘 분석기(Lexical Analyzer)&lt;/b&gt;를 구현하는 과정에서 이전에 한 번 써보았던 &lt;code&gt;unordered_map&lt;/code&gt;를 사용하게되어 &lt;code&gt;unordered_map&lt;/code&gt;을 다시 공부한 내용을 써보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;들어가기에 앞서&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 공부한 내용들은 전부 아래의 링크들에서 학습 및 참고하였습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1679310782615&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;A Proposal to Add Hash Tables to the Standard Library&quot; data-og-description=&quot;X(i, j, n, hf, eq) X a(i, j, n, hf, eq) X Constructs an empty container with at least n buckets, using hf as the hash function and eq as the key equality predicate, and inserts elements from [i, j) into it. Average case O(N) (N is std::distance(i, j)), wor&quot; data-og-host=&quot;www.open-std.org&quot; data-og-source-url=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1456.html&quot; data-og-url=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1456.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1456.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1456.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;A Proposal to Add Hash Tables to the Standard Library&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;X(i, j, n, hf, eq) X a(i, j, n, hf, eq) X Constructs an empty container with at least n buckets, using hf as the hash function and eq as the key equality predicate, and inserts elements from [i, j) into it. Average case O(N) (N is std::distance(i, j)), wor&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.open-std.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1679310792202&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;std::unordered_map - cppreference.com&quot; data-og-description=&quot;(1) (since C++11) (2) (since C++17) Unordered map is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements have average constant-time complexity. Internally, the elements are not sorted in any p&quot; data-og-host=&quot;en.cppreference.com&quot; data-og-source-url=&quot;https://en.cppreference.com/w/cpp/container/unordered_map&quot; data-og-url=&quot;https://en.cppreference.com/w/cpp/container/unordered_map&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://en.cppreference.com/w/cpp/container/unordered_map&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://en.cppreference.com/w/cpp/container/unordered_map&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;std::unordered_map - cppreference.com&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;(1) (since C++11) (2) (since C++17) Unordered map is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements have average constant-time complexity. Internally, the elements are not sorted in any p&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;en.cppreference.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1679310802613&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;unordered_map 클래스&quot; data-og-description=&quot;다양한 길이의 요소 시퀀스를 제어하는 C++ 표준 라이브러리 컨테이너 클래스 'unordered_map'에 대한 API 참조입니다.&quot; data-og-host=&quot;learn.microsoft.com&quot; data-og-source-url=&quot;https://learn.microsoft.com/ko-kr/cpp/standard-library/unordered-map-class?view=msvc-170&quot; data-og-url=&quot;https://learn.microsoft.com/ko-kr/cpp/standard-library/unordered-map-class&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vLlWc/hyR0qdgx24/K9L8b7hdkdOHHkE7Xqf9M0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://learn.microsoft.com/ko-kr/cpp/standard-library/unordered-map-class?view=msvc-170&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://learn.microsoft.com/ko-kr/cpp/standard-library/unordered-map-class?view=msvc-170&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vLlWc/hyR0qdgx24/K9L8b7hdkdOHHkE7Xqf9M0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;unordered_map 클래스&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;다양한 길이의 요소 시퀀스를 제어하는 C++ 표준 라이브러리 컨테이너 클래스 'unordered_map'에 대한 API 참조입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;learn.microsoft.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;unordered_map이란&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;unordered_map&lt;/code&gt;은 &lt;b&gt;C++ 위원회&lt;/b&gt;에서 만든 해시 테이블(Hash Table)을 이용하여 해시맵(Hash Map) 기능을 하는 &lt;code&gt;컨테이너(Container)&lt;/code&gt;입니다.&lt;br /&gt;(정식 도입은 &lt;code&gt;C++11&lt;/code&gt;에서 이루어졌습니다.)&lt;br /&gt;&lt;code&gt;hash&lt;/code&gt;라는 구조체와 함께 &lt;code&gt;unordered_map&lt;/code&gt;, &lt;code&gt;unordered_set&lt;/code&gt;, &lt;code&gt;unordered_multimap&lt;/code&gt;, &lt;code&gt;unordered_multiset&lt;/code&gt; 네 가지가 도입이 되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unordered_map&lt;/code&gt;은 말 그대로 &quot;정렬되지 않은 &lt;code&gt;map&lt;/code&gt;&quot;입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;map&lt;/code&gt;과 동일하게 &lt;code&gt;키(Key)&lt;/code&gt;와 &lt;code&gt;요소(Element)&lt;/code&gt;로 이루어져 있으며 &lt;code&gt;키(Key)&lt;/code&gt;는 중복될 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;평균 시간 복잡도는 O(1)&lt;/b&gt; 입니다.&lt;br /&gt;(단, O(1)의 속도를 유지하려면 요소의 수가 증가할 수록 버킷의 수도 같이 증가해야 함(메모리의 증가))&lt;br /&gt;최악의 상황인 경우에는 O(N) (N은 키의 개수)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unordered_map&lt;/code&gt;은 &lt;code&gt;버킷(Bucket)&lt;/code&gt; 단위로 관리됩니다.&lt;/li&gt;
&lt;li&gt;버킷은 &lt;code&gt;단일 링크드리스트(Singly linked list)&lt;/code&gt;로 이루어져 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insert(특정 위치 삽입)&lt;/code&gt;할 때 최대 O(N * size()) 만큼 걸리는 것으로 보아 특정 위치에 많은 삽입이 일어나는 경우에는 성능 저하 가능성이 높습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;&lt;/code&gt; 필요합니다.&lt;/li&gt;
&lt;li&gt;std namespace를 사용해야합니다.&lt;br /&gt;(std::unordered_map)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;unordered_map 생성자&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1679312508385&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// C++11
// Key       : 키 형식
// T         : 매핑 형식
// Hash      : 해시에 사용할 함수 개체 형식
// KeyEqual  : 비교에 사용할 함수 개체 형식
// Allocator : 할당자
template&amp;lt;
    class Key,
    class T,
    class Hash = std::hash&amp;lt;Key&amp;gt;,
    class KeyEqual = std::equal_to&amp;lt;Key&amp;gt;,
    class Allocator = std::allocator&amp;lt; std::pair&amp;lt;const Key, T&amp;gt; &amp;gt;
&amp;gt; class unordered_map;

// C++17
// Key       : 키 형식
// T         : 매핑 형식
// Hash      : 해시에 사용할 함수 개체 형식
// KeyEqual  : 비교에 사용할 함수 개체 형식
namespace pmr 
{
template &amp;lt;
    class Key,
    class T,
    class Hash = std::hash&amp;lt;Key&amp;gt;,
    class KeyEqual = std::equal_to&amp;lt;Key&amp;gt;
&amp;gt; using unordered_map = std::unordered_map&amp;lt;Key, T, Hash, KeyEqual,
                            std::pmr::polymorphic_allocator&amp;lt;std::pair&amp;lt;const Key,T&amp;gt;&amp;gt;&amp;gt;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;C++11&lt;/code&gt;과 &lt;code&gt;C++17&lt;/code&gt;의 차이점은 &lt;code&gt;Allocator&lt;/code&gt;의 차이가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 &lt;code&gt;Hash&lt;/code&gt;, &lt;code&gt;KeyEqual&lt;/code&gt;, &lt;code&gt;Allocator&lt;/code&gt;는 기본값을 사용하며 &lt;code&gt;Key&lt;/code&gt;와 &lt;code&gt;T&lt;/code&gt;만 선언하여 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679312706249&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;

int main()
{
    // 키 타입은 string, 데이터는 int
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap;
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터 추가 (insert)&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1679312808201&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap;
    // 방법 1
    umap.insert(std::make_pair(&quot;Hi&quot;, 11));
    // 방법 2
    umap.insert(std::unordered_map&amp;lt;std::string, int&amp;gt;::value_type(&quot;My&quot;, 22));
    // 방법 3
    umap.insert({ &quot;Hello&quot;, 33 });
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 위와 같은 방법이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;반복자 (iterator)&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;vector&lt;/code&gt;, &lt;code&gt;deque&lt;/code&gt; 등의 &lt;code&gt;컨테이너(Container)&lt;/code&gt;들과 마찬가지로 정방향, 역방향 반복자를 지원합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679314080401&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap = 
    {
        std::make_pair(&quot;Hi&quot;, 1),
        std::make_pair(&quot;Hello&quot;, 3),
        std::make_pair(&quot;World&quot;, 4),
        std::make_pair(&quot;!!!&quot;, 6)
    };
    
    // 정방향
    // auto it = umap.begin(); 도 가능
    std::unordered_map&amp;lt;std::string, int&amp;gt;::iterator it = umap.begin();
    while (it != umap.end())
    {
        // Do something ...
        ++it;
    }
    
    // 역방향
    // auto cit = umap.cbegin(); 도 가능
    std::unordered_map&amp;lt;std::string, int&amp;gt;::const_iterator cit = umap.cbegin();
    while (cit != umap.cend())
    {
        // Do something ...
        ++cit;
    }
    
    // 정방향 (버킷의 크기 만큼 이동)
    // auto itb = umap.begin(umap.bucket(&quot;Hi&quot;)); 도 가능
    std::unordered_map&amp;lt;std::string, int&amp;gt;::iterator it = umap.begin(umap.bucket(&quot;Hi&quot;));
    
    // 역방향 (버킷의 크기 만큼 이동)
    // auto citb = umap.cbegin(umap.bucket(&quot;Hi&quot;)); 도 가능
    std::unordered_map&amp;lt;std::string, int&amp;gt;::const_iterator citb = umap.cbegin(umap.bucket(&quot;Hi&quot;));
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;버킷단위로 관리하는 만큼 버킷의 크기만큼 이동하는 반복자도 지원합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터 삭제 (erase)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;unordered_map&lt;/code&gt;의 &lt;code&gt;erase&lt;/code&gt;는 &lt;code&gt;map&lt;/code&gt;의 &lt;code&gt;erase&lt;/code&gt;와 동일한 동작을 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679313550982&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap = 
    {
        std::make_pair(&quot;Hi&quot;, 1),
        std::make_pair(&quot;Hello&quot;, 3),
        std::make_pair(&quot;World&quot;, 4),
        std::make_pair(&quot;!!!&quot;, 6)
    };
    
    std::unordered_map&amp;lt;std::string, int&amp;gt;::iterator it = umap.begin();
    umap.erase(it);	    // { &quot;Hi&quot;,1 }   제거
    umap.erase(&quot;!!!&quot;);  // { &quot;!!!&quot;, 6 } 제거
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;요소 값(Element) (at, [ ])&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 &lt;code&gt;키(Key)&lt;/code&gt;의 &lt;code&gt;요소 값(Element)&lt;/code&gt;을 받아오는 기능입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679314728921&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap = 
    {
        std::make_pair(&quot;Hi&quot;, 1),
        std::make_pair(&quot;Hello&quot;, 3),
        std::make_pair(&quot;World&quot;, 4),
        std::make_pair(&quot;!!!&quot;, 6)
    };
    
    printf(&quot;Hi: %d\n&quot;, umap.at(&quot;Hi&quot;));     // Hi: 1
    printf(&quot;Hello: %d\n&quot;, umap[&quot;Hello&quot;]);  // Hello: 3
    umap[&quot;Hello&quot;] = 5;
    printf(&quot;Hello: %d\n&quot;, umap[&quot;Hello&quot;]);  // Hello: 5
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;[ ] operator&lt;/code&gt;의 경우에는 값을 대입할 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;키(Key)의 요소 값(Element) 찾기 (find)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;키(Key)&lt;/code&gt;의 &lt;code&gt;요소 값(Element)&lt;/code&gt;을 찾는 기능입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679314937358&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap = 
    {
        std::make_pair(&quot;Hi&quot;, 1),
        std::make_pair(&quot;Hello&quot;, 3),
        std::make_pair(&quot;World&quot;, 4),
        std::make_pair(&quot;!!!&quot;, 6)
    };
    
    std::unordered_map&amp;lt;std::string, int&amp;gt;::iterator it = umap.find(&quot;World&quot;);
    
    // 키값을 찾지 못했다면 iterator는 end()와 같음
    if (it != umap.end())
        printf(&quot;Find: [%s, %d]\n&quot;, it-&amp;gt;first, it-&amp;gt;second);  // Find: [World, 4]
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;키(Key)의 요소 개수 찾기 (count)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;find()&lt;/code&gt;와 비슷하지만 &lt;code&gt;find()&lt;/code&gt;는 &lt;code&gt;키(Key)와 요소(Element)&lt;/code&gt;를 반환하는 대신에 &lt;code&gt;count()&lt;/code&gt;는 단순히 개수만 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1679315768103&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap = 
    {
        std::make_pair(&quot;Hi&quot;, 1),
        std::make_pair(&quot;Hello&quot;, 3),
        std::make_pair(&quot;World&quot;, 4),
        std::make_pair(&quot;!!!&quot;, 6)
    };
    
    // 키값을 찾으면 반환되는 개수는 1 (키값이 중복되지 않으므로 요소의 개수도 1개)
    if (umap.count(&quot;Hi&quot;) == 1)
        printf(&quot;Find: Hi&quot;);
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 libcxx에서 &lt;code&gt;count()&lt;/code&gt;를 구현할 때 &lt;code&gt;find()&lt;code&gt;를 사용했다고 합니다.&lt;/code&gt;&lt;/code&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1679315895741&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;unordered_map: which one is faster find() or count()?&quot; data-og-description=&quot;What is the fastest way to figure out if an unordered_map container has an item with a specified key?&quot; data-og-host=&quot;stackoverflow.com&quot; data-og-source-url=&quot;https://stackoverflow.com/a/14159799&quot; data-og-url=&quot;https://stackoverflow.com/questions/14159682/unordered-map-which-one-is-faster-find-or-count&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhndy8/hyR0zaguP0/NDJsX1RypC1LB7nnOIenP0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/a/14159799&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://stackoverflow.com/a/14159799&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhndy8/hyR0zaguP0/NDJsX1RypC1LB7nnOIenP0/img.png?width=316&amp;amp;height=316&amp;amp;face=0_0_316_316');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;unordered_map: which one is faster find() or count()?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;What is the fastest way to figure out if an unordered_map container has an item with a specified key?&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;stackoverflow.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;요소가 비어있는지 확인 (empty), 전체 요소의 개수 (size)&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 &lt;code&gt;컨테이너(Container)&lt;code&gt;에서도 제공하는 &lt;code&gt;empty()&lt;/code&gt;와 &lt;code&gt;size()&lt;/code&gt;입니다.&lt;/code&gt;&lt;/code&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679315311510&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_map&amp;gt;
#include &amp;lt;iostream&amp;gt;

int main()
{
    std::unordered_map&amp;lt;std::string, int&amp;gt; umap;
    
    if (umap.empty())
        printf(&quot;umap is empty.\n&quot;);
        
    umap.insert(std::make_pair(&quot;Hi&quot;, 1));
    umap.insert(std::make_pair(&quot;Hello&quot;, 3));
    umap.insert(std::make_pair(&quot;World&quot;, 4));
    umap.insert(std::make_pair(&quot;!!!&quot;, 6));
    
    if (umap.empty() == false)
        printf(&quot;umap count: %d\n&quot;, umap.size());
    
    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/C++</category>
      <category>C++</category>
      <category>c++11</category>
      <category>hash_map</category>
      <category>unordered_map</category>
      <category>맵</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/197</guid>
      <comments>https://eskeptor.tistory.com/197#entry197comment</comments>
      <pubDate>Mon, 20 Mar 2023 21:57:04 +0900</pubDate>
    </item>
    <item>
      <title>[C++/Console] 테트리스 만들어 보기 - 6 (바닥 충돌, 블럭 랜덤 생성)</title>
      <link>https://eskeptor.tistory.com/196</link>
      <description>&lt;figure id=&quot;og_1678099562022&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[C++/Console] 테트리스 만들어 보기 - 5 (충돌 판정 - 벽, 블럭)&quot; data-og-description=&quot;[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임) [C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) [C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) [C++/Console] &quot; data-og-host=&quot;eskeptor.tistory.com&quot; data-og-source-url=&quot;https://eskeptor.tistory.com/195&quot; data-og-url=&quot;https://eskeptor.tistory.com/195&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/DUYsx/hyRRH7iyMh/91BAJMZ8krCihyFik1IAv0/img.gif?width=257&amp;amp;height=508&amp;amp;face=0_0_257_508,https://scrap.kakaocdn.net/dn/dRmveS/hyRRE3NUSg/gg5M0lm2wbEoxJC9fl80IK/img.gif?width=257&amp;amp;height=508&amp;amp;face=0_0_257_508&quot;&gt;&lt;a href=&quot;https://eskeptor.tistory.com/195&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://eskeptor.tistory.com/195&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/DUYsx/hyRRH7iyMh/91BAJMZ8krCihyFik1IAv0/img.gif?width=257&amp;amp;height=508&amp;amp;face=0_0_257_508,https://scrap.kakaocdn.net/dn/dRmveS/hyRRE3NUSg/gg5M0lm2wbEoxJC9fl80IK/img.gif?width=257&amp;amp;height=508&amp;amp;face=0_0_257_508');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 5 (충돌 판정 - 벽, 블럭)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임) [C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) [C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) [C++/Console]&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eskeptor.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에는 충돌 판정에 관련하여 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 바닥 충돌(또는 블럭 충돌) 및 블럭 랜덤 생성에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;바닥&amp;nbsp; 충돌 (또는 블럭 충돌)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에 이어서 바닥에 충돌하였을 때 감지하는 방법을 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바닥을 확인하는 &lt;code&gt;CheckBottom 함수&lt;/code&gt;를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678100211759&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CheckBottom()
{
    if (IsMoveAvailable(0, 1))
        return;

    // 다음 줄로 움직일 수 없다면 현재 블럭을 포함하여 맵에 저장
    memcpy_s(g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);

    // 플레이어의 위치를 초기 위치로 변경
    g_player.SetPosition(START_POS_X, START_POS_Y);
    // 플레이어의 블럭 설정
    g_player.SetBlock(1);
    // 플레이어의 블럭 방향 설정
    g_player.SetDirection(CPlayer::eDirection::Dir0);

    g_prevPlayerData = g_player;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이 &lt;code&gt;CheckBottom 함수&lt;/code&gt;는&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678100273938&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main(void)
{
    InitGame();

    while (true)
    {
        InputKey();
        CalcPlayer();

        CheckBottom();        // &amp;lt;-- Player가 움직인 이후에 바닥 확인
        Render(3, 1);

        ClearScreen();
        BufferFlip();
        Sleep(1);
    }

    DestroyGame();

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;CalcPlayer 함수&lt;/code&gt; 다음에 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(플레이어가 움직인 이후에 바닥을 확인하는 매커니즘입니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 수정하고 실행하게 되면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;499&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJZK7s/btr2sX1nU7r/5AZAItVcL1kBM5QqfI2ldK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJZK7s/btr2sX1nU7r/5AZAItVcL1kBM5QqfI2ldK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJZK7s/btr2sX1nU7r/5AZAItVcL1kBM5QqfI2ldK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bJZK7s/btr2sX1nU7r/5AZAItVcL1kBM5QqfI2ldK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;234&quot; height=&quot;499&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;499&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 바닥 또는 더 이상 내려가지 못하는 곳으로 가게 되면 다음 블럭으로 넘어가게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;랜덤 블럭 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 블럭을 랜덤으로 생성할 수 있도록 코드를 작성하여 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 C++에서 사용하는 랜덤 함수에 대해서 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크게 2가지가 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678100796442&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// C언어 기반 rand 함수 사용
#include &amp;lt;stdlib.h&amp;gt;         // 랜덤 함수(srand, rand)가 있는 헤더 파일
#include &amp;lt;time.h&amp;gt;           // 시간 함수(time)가 있는 헤더 파일

srand(time(NULL));          // 랜덤 시드 설정 (time(NULL)은 1970.1.1의 시간 값을 반환)
int nRand = rand() % 10;    // 0 ~ 9까지 랜덤 값을 반환&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C언어 기반의 랜덤 함수와&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678101060779&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// C++11 기반의 랜덤 함수 (MT19937 사용)
#include &amp;lt;random&amp;gt;               // 랜덤 함수가 들어있는 헤더파일

std::random_device rdDevice;    // 랜덤 시드용 디바이스
std::mt19937 gen(rdDevice());   // 난수 생성 엔진(메르센 트위스터) 초기화
std::uniform_int_distribution&amp;lt;int&amp;gt; dist(0, 9);   // 0 ~ 9 랜덤 값 생성
int nRandom = dist(gen);        // 랜덤 값 생성&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++11에서 제공하는 랜덤 함수가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법들 중 후자의 방법(C++11 기반)을 사용하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;stConsole 구조체&lt;/code&gt;에 랜덤 관련 변수를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678101318578&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Console Structure
struct stConsole
{
    // 생략 ....

    // Random Seed
    random_device rdDevice;
    // Random Generation
    mt19937 rdGen;
    // Random Distribution (블럭)
    uniform_int_distribution&amp;lt;int&amp;gt; rdBlockDist;
    // Random Distribution (블럭의 방향)
    uniform_int_distribution&amp;lt;int&amp;gt; rdDirDist;

    stConsole()
        : hConsole(nullptr), hBuffer{ nullptr, }, nCurBuffer(0)
        , rdGen(rdDevice()), rdBlockDist(0, 6), rdDirDist(CPlayer::eDirection::Dir0, CPlayer::eDirection::Dir270)
    {}
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 랜덤으로 블럭을 생성하는 &lt;code&gt;RandomBlock 함수&lt;/code&gt;와 랜덤으로 블럭의 방향을 생성하는 &lt;code&gt;RandomDirection 함수&lt;/code&gt;를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678101441698&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
블럭 랜덤 생성
*/
int RandomBlock()
{
    return g_console.rdBlockDist(g_console.rdGen);
}

/**
블럭의 방향 랜덤 생성
*/
int RamdomDirection()
{
    return g_console.rdDirDist(g_console.rdGen);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 모든 상황에서 블럭을 랜덤한 방향으로 생성하도록 해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1678101612819&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// InitGame 함수 변경
void InitGame(bool bInitConsole = true)
{
    // Initialize Player Data
    {
        g_player.SetPosition(START_POS_X, START_POS_Y);
        g_player.SetXPositionRange(-1, MAP_WIDTH);
        g_player.SetYPositionRange(0, MAP_HEIGHT);
        
        // 블럭 랜덤 생성
        g_player.SetBlock(RandomBlock());
        // 블럭 방향 랜덤 생성
        g_player.SetDirection((CPlayer::eDirection)RamdomDirection());
        
        g_player.SetGameScore(0);
        g_player.SetGameOver(false);

        g_prevPlayerData = g_player;
    }
    
    // 생략 ....
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;InitGame 함수&lt;/code&gt;에서 블럭을 랜덤으로 생성하도록 변경 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678101711561&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// CheckBottom 함수 변경
void CheckBottom()
{
    if (IsMoveAvailable(0, 1))
        return;

    memcpy_s(g_nArrMapBackup, sizeof(int) * MAP_WIDTH * MAP_HEIGHT, g_nArrMap, sizeof(int) * MAP_WIDTH * MAP_HEIGHT);

    g_player.SetPosition(START_POS_X, START_POS_Y);
    // 블럭 랜덤 생성
    g_player.SetBlock(RandomBlock());
    // 블럭 방향 랜덤 생성
    g_player.SetDirection((CPlayer::eDirection)RamdomDirection());

    g_prevPlayerData = g_player;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;CheckBottom 함수&lt;/code&gt;에서 블럭을 랜덤으로 생성하도록 변경 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실행하여 봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;499&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bte8Cb/btr2tCpc7Rm/dVxifJZkwLogzoFmw1TC6K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bte8Cb/btr2tCpc7Rm/dVxifJZkwLogzoFmw1TC6K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bte8Cb/btr2tCpc7Rm/dVxifJZkwLogzoFmw1TC6K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bte8Cb/btr2tCpc7Rm/dVxifJZkwLogzoFmw1TC6K/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;234&quot; height=&quot;499&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;234&quot; data-origin-height=&quot;499&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 바닥 또는 블럭에 충돌했을 때 다음 블럭으로(랜덤하게) 나오도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 자동으로 블럭이 내려오도록 하고 라인을 형성하였을 때 지워지면서 점수가 올라가도록 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;현재 까지의 진행 프로젝트 다운로드&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/z47rc/btr2sXG81dJ/NJPZ3Frsja8Pqn2tLT3rdK/TetrisCpp_6%ED%8E%B8.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;TetrisCpp_6편.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Study/C++</category>
      <category>Block</category>
      <category>C++</category>
      <category>Collision</category>
      <category>mt19937</category>
      <category>rand</category>
      <category>Tetris</category>
      <category>랜덤</category>
      <category>벽</category>
      <category>충돌</category>
      <category>테트리스</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/196</guid>
      <comments>https://eskeptor.tistory.com/196#entry196comment</comments>
      <pubDate>Mon, 6 Mar 2023 20:30:20 +0900</pubDate>
    </item>
    <item>
      <title>[C++/Console] 테트리스 만들어 보기 - 5 (충돌 판정 - 벽, 블럭)</title>
      <link>https://eskeptor.tistory.com/195</link>
      <description>&lt;figure id=&quot;og_1676890431972&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임)&quot; data-og-description=&quot;[C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) [C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) [C++/Console] 테트리스 만들어 보기 - 1 (간단 소개 및 더블 버퍼링) Window 환&quot; data-og-host=&quot;eskeptor.tistory.com&quot; data-og-source-url=&quot;https://eskeptor.tistory.com/194&quot; data-og-url=&quot;https://eskeptor.tistory.com/194&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gmYdH/hyRHiHgAQ6/nN8K5v5EoVc0rtAZ2iBwp0/img.gif?width=251&amp;amp;height=494&amp;amp;face=0_0_251_494,https://scrap.kakaocdn.net/dn/cAiT0R/hyRHyQRxSA/9vA97DDIOASMT6sU18kVqK/img.gif?width=251&amp;amp;height=494&amp;amp;face=0_0_251_494,https://scrap.kakaocdn.net/dn/oKcUv/hyRHyXDDRP/Ke0heoEvUkZOyWUAulmLZ0/img.png?width=1021&amp;amp;height=497&amp;amp;face=0_0_1021_497&quot;&gt;&lt;a href=&quot;https://eskeptor.tistory.com/194&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://eskeptor.tistory.com/194&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gmYdH/hyRHiHgAQ6/nN8K5v5EoVc0rtAZ2iBwp0/img.gif?width=251&amp;amp;height=494&amp;amp;face=0_0_251_494,https://scrap.kakaocdn.net/dn/cAiT0R/hyRHyQRxSA/9vA97DDIOASMT6sU18kVqK/img.gif?width=251&amp;amp;height=494&amp;amp;face=0_0_251_494,https://scrap.kakaocdn.net/dn/oKcUv/hyRHyXDDRP/Ke0heoEvUkZOyWUAulmLZ0/img.png?width=1021&amp;amp;height=497&amp;amp;face=0_0_1021_497');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰) [C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) [C++/Console] 테트리스 만들어 보기 - 1 (간단 소개 및 더블 버퍼링) Window 환&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eskeptor.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에는 플레이어(블럭)의 움직임에 관련하여 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 플레이어(블럭) 충돌 판정에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;충돌 판정&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sYSnk/btrZ7G8NMEe/enUfHlMAmdwt7D1GjOJkWk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sYSnk/btrZ7G8NMEe/enUfHlMAmdwt7D1GjOJkWk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sYSnk/btrZ7G8NMEe/enUfHlMAmdwt7D1GjOJkWk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/sYSnk/btrZ7G8NMEe/enUfHlMAmdwt7D1GjOJkWk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;257&quot; height=&quot;508&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에 했던 프로젝트를 실행해서 움직여보면 좌, 우, 하단 끝에 도달하여도 계속 가는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 방지하기 위해서는 충돌 판정을 통해서 움직이지 못하도록 해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 어떻게 하면 충돌 판정을 시킬 수 있을 까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1676891124860&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InputKey()
{
    int nKey = 0;

    if (_kbhit() &amp;gt; 0)
    {
        nKey = _getch();

        switch (nKey)
        {
            case eKeyCode::KEY_UP:
            {
                break;
            }
            case eKeyCode::KEY_DOWN:
            {
                g_player.AddPosition(0, 1);    // &amp;lt;-- 움직이기
                break;
            }
            case eKeyCode::KEY_LEFT:
            {
                g_player.AddPosition(-1, 0);   // &amp;lt;-- 움직이기
                break;
            }
            case eKeyCode::KEY_RIGHT:
            {
                g_player.AddPosition(1, 0);    // &amp;lt;-- 움직이기
                break;
            }
            case eKeyCode::KEY_SPACE:
            {
                break;
            }
            case eKeyCode::KEY_R:
            {
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 우리는 &lt;code&gt;InputKey 함수&lt;/code&gt;에서 키를 누름과 동시에 플레이어(블럭)의 좌표를 증가하도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 누름과 동시에 이동을 하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 좌표를 증가시키기 전에 그 위치로 이동해도 되는지 확인하는 과정(충돌을 하는지 안하는지)을 거치게 되면 벽을 넘어서지 못하도록 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 이전 맵의 데이터를 기록하는 배열을 전역으로 하나 만듭니다.&lt;/p&gt;
&lt;pre id=&quot;code_1676892247832&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Map Data (Backup Data)
int g_nArrMapBackup[MAP_HEIGHT][MAP_WIDTH] = { 0, };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제부터 이 배열은 &lt;code&gt;이전의 테트리스 맵을 백업&lt;/code&gt;하도록 할겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이전이라고 함은 현재 블럭이 ㄴ 이고 이전 블럭이 ㅡ 일 때 ㄴ 블럭 이전의 맵 데이터)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 충돌을 확인하는 &lt;code&gt;IsCollision 함수&lt;/code&gt;를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1676892496518&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// pBlock : 블럭 데이터
// coordPlayer : 블럭의 위치
bool IsCollision(int* pBlock, const COORD&amp;amp; coordPlayer)
{
    int nColision = 0;

    for (int nY = 0; nY &amp;lt; BLOCK_HEIGHT; ++nY)
    {
        for (int nX = 0; nX &amp;lt; BLOCK_WIDTH; ++nX)
        {
            // 벽 충돌 유무
            nColision = pBlock[(nY * BLOCK_HEIGHT) + nX] &amp;amp; (g_nArrMapBackup[coordPlayer.Y + nY][coordPlayer.X + nX] &amp;lt;&amp;lt; 1);
            // 다른 블럭과 충돌 유무
            nColision += pBlock[(nY * BLOCK_HEIGHT) + nX] &amp;amp; g_nArrMapBackup[coordPlayer.Y + nY][coordPlayer.X + nX];

            // 벽 또는 블럭과 충돌 했다면 충돌로 판정
            if (nColision &amp;gt; 0)
                return true;
        }
    }

    return false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 &lt;code&gt;IsCollision 함수&lt;/code&gt;를 이용하여 키가 눌렸을 때 그 위치로 이동할 수 있는지 유무를 판단하는 함수인 &lt;code&gt;IsMoveAvailable 함수&lt;/code&gt;를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1676892670171&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// nXAdder : 플레이어(블럭)이 이동할 X 위치(증가)
// nYAdder : 플레이어(블럭)이 이동할 Y 위치(증가)
bool IsMoveAvailable(int nXAdder, int nYAdder)
{
    // 현재 플레이어의 위치
    COORD coorNext = g_player.GetCursor();
    // 다음 위치를 미리 시뮬레이션
    coorNext.X += nXAdder;
    coorNext.Y += nYAdder;
    // 다음 위치로 이동한 블럭의 데이터
    int* pBlock = GetRotateBlock(g_player.GetBlock(), g_player.GetDirection());

    // 다음 위치로 이동 했을 때 충돌을 했는지 유무
    return !IsCollision(pBlock, coorNext);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;IsMoveAvailable 함수를&lt;/code&gt; 이용하여 충돌 감지하여 벽을 벗어나지 못하도록 해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1676893072351&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InputKey()
{
    int nKey = 0;

    if (_kbhit() &amp;gt; 0)
    {
        nKey = _getch();

        switch (nKey)
        {
            case eKeyCode::KEY_UP:
            {
                break;
            }
            case eKeyCode::KEY_DOWN:
            {
                if (IsMoveAvailable(0, 1))
                    g_player.AddPosition(0, 1);
                break;
            }
            case eKeyCode::KEY_LEFT:
            {
                if (IsMoveAvailable(-1, 0))
                    g_player.AddPosition(-1, 0);
                break;
            }
            case eKeyCode::KEY_RIGHT:
            {
                if (IsMoveAvailable(1, 0))
                    g_player.AddPosition(1, 0);
                break;
            }
            case eKeyCode::KEY_SPACE:
            {
                break;
            }
            case eKeyCode::KEY_R:
            {
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이전의 테트리스 맵을 기억하는 &lt;code&gt;백업용 배열&lt;/code&gt;을 &lt;b&gt;초기화&lt;/b&gt; 합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1676893018771&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InitGame(bool bInitConsole = true)
{
    // Initialize Player Data
    {
        // 생략 ......
    }

    if (bInitConsole)
    {
        // 생략 ......
    }

    // Map Backup
    {
        int nMapSize = sizeof(int) * MAP_WIDTH * MAP_HEIGHT;
        memcpy_s(g_nArrMap, nMapSize, ORIGIN_MAP, nMapSize);
        memcpy_s(g_nArrMapBackup, nMapSize, g_nArrMap, nMapSize);  // &amp;lt;-- 백업맵 초기화
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실행하여 봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XxYZI/btrZ8M8zS7r/Lto1L7Y6Xq8K1CmqSP3NXK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XxYZI/btrZ8M8zS7r/Lto1L7Y6Xq8K1CmqSP3NXK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XxYZI/btrZ8M8zS7r/Lto1L7Y6Xq8K1CmqSP3NXK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/XxYZI/btrZ8M8zS7r/Lto1L7Y6Xq8K1CmqSP3NXK/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;257&quot; height=&quot;508&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;257&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 벽에 닿으면 더이상 움직이지 않게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 블럭이 바닥에 닿았을 때 해당 블럭은 바닥에 남고 다음 블럭이 랜덤으로 생성되는 것에 대해서 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;현재 까지의 진행 프로젝트 다운로드&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/b9wI4A/btrZ7qEW1K6/nPNovbNTWCJnRyUIlJPIp0/TetrisCpp_5%ED%8E%B8.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;TetrisCpp_5편.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Study/C++</category>
      <category>C++</category>
      <category>Collision</category>
      <category>Console</category>
      <category>Tetris</category>
      <category>벽</category>
      <category>블럭</category>
      <category>충돌</category>
      <category>테트리스</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/195</guid>
      <comments>https://eskeptor.tistory.com/195#entry195comment</comments>
      <pubDate>Mon, 20 Feb 2023 20:44:13 +0900</pubDate>
    </item>
    <item>
      <title>[C++/Console] 테트리스 만들어 보기 - 4 (플레이어(블럭) 움직임)</title>
      <link>https://eskeptor.tistory.com/194</link>
      <description>&lt;figure id=&quot;og_1675941890523&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰)&quot; data-og-description=&quot;[C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) [C++/Console] 테트리스 만들어 보기 - 1 (간단 소개 및 더블 버퍼링) Window 환경에서 C++과 Console창을 이용하여 테트리스를 만들어 봅시다. &quot; data-og-host=&quot;eskeptor.tistory.com&quot; data-og-source-url=&quot;https://eskeptor.tistory.com/193&quot; data-og-url=&quot;https://eskeptor.tistory.com/193&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/L7iG9/hyRzo1HID0/NekuqYwMNizJ9WE2eUlBK1/img.png?width=432&amp;amp;height=511&amp;amp;face=0_0_432_511,https://scrap.kakaocdn.net/dn/cG4NTi/hyRzzhRmEg/RPGlAk74slMUxKq2t5D5jk/img.png?width=432&amp;amp;height=511&amp;amp;face=0_0_432_511,https://scrap.kakaocdn.net/dn/2yCpM/hyRxRRV7xm/B1rcZ7K1M5ZUa3PXnfcJA1/img.png?width=432&amp;amp;height=511&amp;amp;face=0_0_432_511&quot;&gt;&lt;a href=&quot;https://eskeptor.tistory.com/193&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://eskeptor.tistory.com/193&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/L7iG9/hyRzo1HID0/NekuqYwMNizJ9WE2eUlBK1/img.png?width=432&amp;amp;height=511&amp;amp;face=0_0_432_511,https://scrap.kakaocdn.net/dn/cG4NTi/hyRzzhRmEg/RPGlAk74slMUxKq2t5D5jk/img.png?width=432&amp;amp;height=511&amp;amp;face=0_0_432_511,https://scrap.kakaocdn.net/dn/2yCpM/hyRxRRV7xm/B1rcZ7K1M5ZUa3PXnfcJA1/img.png?width=432&amp;amp;height=511&amp;amp;face=0_0_432_511');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 3 (화면 출력에 대한 고찰)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭) [C++/Console] 테트리스 만들어 보기 - 1 (간단 소개 및 더블 버퍼링) Window 환경에서 C++과 Console창을 이용하여 테트리스를 만들어 봅시다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eskeptor.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에는 화면 출력에 관련하여 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 플레이어(블럭) 움직이는 처리에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;플레이어(블럭) 클래스&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 플레이어(블럭)의 처리를 도와줄 클래스를 작성하여봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1675943010531&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CPlayer
{
public:
    // Block 방향
    enum eDirection
    {
        Dir0 = 0,
        Dir90,
        Dir180,
        Dir270,

        DirMax
    };

private:   
    int m_nXPos;               // 현재 X 위치
    int m_nMinXPos;            // 움직일 수 있는 최소 X 범위
    int m_nMaxXPos;            // 움직일 수 있는 최대 X 범위
    int m_nYPos;               // 현재 Y 위치
    int m_nMinYPos;            // 움직일 수 있는 최소 Y 범위
    int m_nMaxYPos;            // 움직일 수 있는 최대 Y 범위
    int m_nCurBlock;           // 현재 블록 (인덱스 값)
    eDirection m_eDirection;   // 현재 블록의 방향
    int m_nGameScore;          // 점수
    bool m_bIsGameOver;        // 게임 오버 유무

public:
    /**
    @brief        생성자
    */
    CPlayer(int nXPos = 0, int nYPos = 0, int nCurBlock = 0, eDirection eDir = eDirection::Dir0)
        : m_nXPos(nXPos), m_nYPos(nYPos), m_nCurBlock(nCurBlock), m_eDirection(eDir)
        , m_nMinXPos(0), m_nMinYPos(0), m_nMaxXPos(20), m_nMaxYPos(20)
        , m_nGameScore(0), m_bIsGameOver(false)
    {}

    /**
    @brief        X 위치 범위 설정
    @param        nMinXPos    최소 X 범위
    @param        nMaxXPos    최대 X 범위
    @return
    */
    inline void SetXPositionRange(int nMinXPos, int nMaxXPos)
    {
        m_nMinXPos = nMinXPos;
        m_nMaxXPos = nMaxXPos;
    }

    /**
    @brief        Y 위치 범위 설정
    @param        nMinYPos    최소 Y 범위
    @param        nMaxYPos    최대 Y 범위
    @return
    */
    inline void SetYPositionRange(int nMinYPos, int nMaxYPos)
    {
        m_nMinYPos = nMinYPos;
        m_nMaxYPos = nMaxYPos;
    }

    /**
    @brief        현재 위치 설정
    @param        nXPos        현재 X 위치
    @param        nYPos        현재 Y 위치
    @return
    */
    inline void SetPosition(int nXPos, int nYPos)
    {
        m_nXPos = nXPos;
        m_nYPos = nYPos;
    }

    /**
    @brief        현재 X 위치 설정
    @param        nXPos        현재 X 위치
    @return
    */
    inline void SetXPosition(int nXPos) { m_nXPos = nXPos; }

    /**
    @brief        현재 Y 위치 설정
    @param        nYPos        현재 Y 위치
    @return
    */
    inline void SetYPosition(int nYPos) { m_nYPos = nYPos; }

    /**
    @brief        현재 블록의 방향 설정
    @param        eDir         현재 블록의 방향
    @return
    */
    inline void SetDirection(eDirection eDir) { m_eDirection = eDir; }

    /**
    @brief        현재 블록의 방향을 다음 방향으로 변경 (ex: 90도 -&amp;gt; 180도)
    @param
    @return
    */
    inline void SetNextDirection()
    {
        m_eDirection = m_eDirection + 1 &amp;gt;= eDirection::DirMax ? eDirection::Dir0 : (eDirection)(m_eDirection + 1);
    }

    /**
    @brief        점수 설정
    @param        nScore        점수
    @return
    */
    inline void SetGameScore(int nScore) { m_nGameScore = nScore; }

    /**
    @brief        현재 점수에서 더하는 기능
    @param        nAdder        더할 점수
    @return
    */
    inline void AddGameScore(int nAdder)
    {
        m_nGameScore = m_nGameScore + nAdder &amp;gt;= 0 ? m_nGameScore + nAdder : 0;
    }

    /**
    @brief        게임 오버 설정
    @param        bIsGameOver        게임 오버 상태
    @return
    */
    inline void SetGameOver(bool bIsGameOver) { m_bIsGameOver = bIsGameOver; }

    /**
    @brief        현재 위치에서 더하는 기능
    @param        nXAdder        X 위치 증가값
    @param        nYAdder        Y 위치 증가값
    @return
    */
    inline void AddPosition(int nXAdder, int nYAdder)
    {
        m_nXPos = (m_nXPos + nXAdder &amp;gt;= m_nMinXPos) ? (m_nXPos + nXAdder &amp;lt;= m_nMaxXPos ? m_nXPos + nXAdder : m_nMaxXPos) : m_nMinXPos;
        m_nYPos = (m_nYPos + nYAdder &amp;gt;= m_nMinYPos) ? (m_nYPos + nYAdder &amp;lt;= m_nMaxYPos ? m_nYPos + nYAdder : m_nMaxYPos) : m_nMinYPos;
    }

    /**
    @brief        현재 블럭을 설정 (인덱스 값)
    @param        nBlock        현재 블럭 (인덱스 값)
    @return
    */
    inline void SetBlock(int nBlock) { m_nCurBlock = nBlock; }

    /**
    @brief        현재 X 위치 반환
    @param        
    @return       현재 X 위치
    */
    inline int GetXPosition() const { return m_nXPos; }

    /**
    @brief        현재 Y 위치 반환
    @param
    @return       현재 Y 위치
    */
    inline int GetYPosition() const { return m_nYPos; }
    
    /**
    @brief        현재 블럭 반환 (인덱스 값)
    @param
    @return       현재 블럭 (인덱스 값)
    */
    inline int GetBlock() const { return m_nCurBlock; }
    
    /**
    @brief        현재 블럭의 방향 반환
    @param
    @return       현재 블럭의 방향
    */
    inline eDirection GetDirection() const { return m_eDirection; }

    /**
    @brief        현재 블럭의 다음 방향 반환
    @param
    @return       현재 블럭의 다음 방향
    */
    inline eDirection GetNextDirection() const
    {
        return (m_eDirection + 1 &amp;gt;= eDirection::DirMax) ? eDirection::Dir0 : (eDirection)(m_eDirection + 1);
    }

    /**
    @brief        현재 위치 반환 (COORD형)
    @param
    @return       현재 위치 (COORD형)
    */
    inline COORD GetCursor() const
    {
        COORD cursor{ (SHORT)m_nXPos, (SHORT)m_nYPos };
        return cursor;
    }

    /**
    @brief        점수 반환
    @param
    @return       점수
    */
    inline int GetGameScore() const { return m_nGameScore; }

    /**
    @brief        게임 오버 상태 반환
    @param
    @return       게임 오버 상태
    */
    inline bool GetGameOver() const { return m_bIsGameOver; }

    CPlayer&amp;amp; operator=(CPlayer&amp;amp; player)
    {
        m_nXPos = player.m_nXPos;
        m_nYPos = player.m_nYPos;
        m_nCurBlock = player.m_nCurBlock;
        m_eDirection = player.m_eDirection;
        m_nMinXPos = player.m_nMinXPos;
        m_nMinYPos = player.m_nMinYPos;
        m_nMaxXPos = player.m_nMaxXPos;
        m_nMaxYPos = player.m_nMaxYPos;

        return *this;
    }

    friend bool operator==(const CPlayer&amp;amp; player1, const CPlayer&amp;amp; player2)
    {
        return (player1.m_nXPos == player2.m_nXPos) &amp;amp;&amp;amp;
            (player1.m_nYPos == player2.m_nYPos) &amp;amp;&amp;amp;
            (player1.m_nCurBlock == player2.m_nCurBlock) &amp;amp;&amp;amp;
            (player1.m_eDirection == player2.m_eDirection) &amp;amp;&amp;amp;
            (player1.m_nMinXPos == player2.m_nMinXPos) &amp;amp;&amp;amp;
            (player1.m_nMinYPos == player2.m_nMinYPos) &amp;amp;&amp;amp; 
            (player1.m_nMaxXPos == player2.m_nMaxXPos) &amp;amp;&amp;amp;
            (player1.m_nMaxYPos == player2.m_nMaxYPos);
    }

    friend bool operator!=(const CPlayer&amp;amp; player1, const CPlayer&amp;amp; player2)
    {
        return !(player1 == player2);
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 설명들은 소스에 있으니 읽어보시면 이해가 될 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 플레이어(블럭)를 전역으로 선언합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675943093405&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Player Data
CPlayer g_player;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;키보드 입력 처리&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1675941972623&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭)&quot; data-og-description=&quot;[C++/Console] 테트리스 만들어 보기 - 1 (간단 소개 및 더블 버퍼링) Window 환경에서 C++과 Console창을 이용하여 테트리스를 만들어 봅시다. 명령 프롬프트의 환경설정 테트리스에서 사용하는 특수 문&quot; data-og-host=&quot;eskeptor.tistory.com&quot; data-og-source-url=&quot;https://eskeptor.tistory.com/192&quot; data-og-url=&quot;https://eskeptor.tistory.com/192&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cnseON/hyRxNPCv7U/N1UI3wFewLkiXQ5qon3fg0/img.png?width=340&amp;amp;height=183&amp;amp;face=0_0_340_183,https://scrap.kakaocdn.net/dn/fJR6s/hyRxV7SrwK/S9EB1uGxXPV6HzkILlxkJK/img.png?width=340&amp;amp;height=183&amp;amp;face=0_0_340_183,https://scrap.kakaocdn.net/dn/cxYRnR/hyRzDEzqKr/R4BQkQJP19HNIDcrJF0RAK/img.png?width=505&amp;amp;height=214&amp;amp;face=0_0_505_214&quot;&gt;&lt;a href=&quot;https://eskeptor.tistory.com/192&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://eskeptor.tistory.com/192&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cnseON/hyRxNPCv7U/N1UI3wFewLkiXQ5qon3fg0/img.png?width=340&amp;amp;height=183&amp;amp;face=0_0_340_183,https://scrap.kakaocdn.net/dn/fJR6s/hyRxV7SrwK/S9EB1uGxXPV6HzkILlxkJK/img.png?width=340&amp;amp;height=183&amp;amp;face=0_0_340_183,https://scrap.kakaocdn.net/dn/cxYRnR/hyRzDEzqKr/R4BQkQJP19HNIDcrJF0RAK/img.png?width=505&amp;amp;height=214&amp;amp;face=0_0_505_214');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 2 (키보드 입력 및 블럭)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[C++/Console] 테트리스 만들어 보기 - 1 (간단 소개 및 더블 버퍼링) Window 환경에서 C++과 Console창을 이용하여 테트리스를 만들어 봅시다. 명령 프롬프트의 환경설정 테트리스에서 사용하는 특수 문&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;eskeptor.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 키보드 입력에 관련한 처리는 2번 챕터에서 알아보았었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675942017704&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InputKey()
{
    int nKey = 0;

    // 키입력이 감지되었을 때
    if (_kbhit() &amp;gt; 0)
    {
        // 입력된 키를 받아온다.
        nKey = _getch();

        switch (nKey)
        {
            case eKeyCode::KEY_UP:    // 방향키 위를 눌렀을 때
            {
                break;
            }
            case eKeyCode::KEY_DOWN:  // 방향키 아래를 눌렀을 때
            {
                break;
            }
            case eKeyCode::KEY_LEFT:  // 방향키 왼쪽을 눌렀을 때
            {
                break;
            }
            case eKeyCode::KEY_RIGHT: // 방향키 오른쪽을 눌렀을 때
            {
                break;
            }
            case eKeyCode::KEY_SPACE: // 스페이스바를 눌렀을 때
            {
                break;
            }
            case eKeyCode::KEY_R:     // R키를 눌렀을 때
            {
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;code&gt;InputKey 함수&lt;/code&gt;를 작성하였었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에 플레이어(블럭)의 좌표를 움직이도록 함수를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675943248521&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InputKey()
{
    int nKey = 0;

    if (_kbhit() &amp;gt; 0)
    {
        nKey = _getch();

        switch (nKey)
        {
            case eKeyCode::KEY_UP:
            {
                // 나중에 블럭 바로 내리기에 사용
                break;
            }
            case eKeyCode::KEY_DOWN:
            {
                // 아래로 1칸 이동 (Y좌표로 1증가)
                g_player.AddPosition(0, 1);
                break;
            }
            case eKeyCode::KEY_LEFT:
            {
                // 왼쪽으로 1칸 이동 (X좌표로 1감소)
                g_player.AddPosition(-1, 0);
                break;
            }
            case eKeyCode::KEY_RIGHT:
            {
                // 오른쪽으로 1칸 이동 (X좌표로 1증가)
                g_player.AddPosition(1, 0);
                break;
            }
            case eKeyCode::KEY_SPACE:
            {
                // 나중에 블럭 회전에 사용
                break;
            }
            case eKeyCode::KEY_R:
            {
                // 나중에 초기화에 사용
                break;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 플레이어(블럭)의 이동을 구현하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;Render 함수&lt;/code&gt;와 &lt;code&gt;CalcPlayer&lt;/code&gt;를 변경해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 고정된 위치에 플레이어(블럭)를 그렸다면 지금은 플레이어(블럭)의 실시간 위치에 맞게 그리도록 변경해야합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675943614694&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CalcPlayer()
{
    // 현재 플레이어(블럭) 위치를 받아온다.
    COORD playerCursor = g_player.GetCursor();

    // 현재 블럭의 방향에 따른 모양을 받아온다.
    int* pBlock = GetRotateBlock(g_player.GetBlock(), g_player.GetDirection());
    for (int nY = 0; nY &amp;lt; BLOCK_HEIGHT; ++nY)
    {
        for (int nX = 0; nX &amp;lt; BLOCK_WIDTH; ++nX)
        {
            if (pBlock[(nY * BLOCK_HEIGHT) + nX])
                g_nArrMap[playerCursor.Y + nY][playerCursor.X + nX] = pBlock[(nY * BLOCK_HEIGHT) + nX];
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;code&gt;GetRotateBlock&lt;/code&gt;라는 함수를 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 블럭의 방향에 따라서 블럭의 모양을 반환하는 함수로 반환 값은 일차원배열로 나옵니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675943847995&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 블럭 데이터 (전역 변수)
int* g_pCurBlock = nullptr;

// nBlockIdx : 블럭의 인덱스
// eDir : 블럭의 방향
int* GetRotateBlock(int nBlockIdx, CPlayer::eDirection eDir)
{
    // 이전 블럭의 데이터가 있다면 제거
    if (g_pCurBlock != nullptr)
    {
        delete[] g_pCurBlock;
        g_pCurBlock = nullptr;
    }

    // 새로운 블럭 할당
    g_pCurBlock = new int[BLOCK_HEIGHT * BLOCK_WIDTH];
    int nMemSize = sizeof(int) * BLOCK_HEIGHT * BLOCK_WIDTH;
    memcpy_s(g_pCurBlock, nMemSize, BLOCKS[nBlockIdx], nMemSize);

    // 블럭 회전
    for (int nRot = 0; nRot &amp;lt; (int)eDir; ++nRot)
    {
        int nTemps[BLOCK_HEIGHT * BLOCK_WIDTH] = { 0, };

        for (int nY = 0; nY &amp;lt; BLOCK_HEIGHT; ++nY)
        {
            for (int nX = 0; nX &amp;lt; BLOCK_WIDTH; ++nX)
            {
                nTemps[(nX * BLOCK_WIDTH) + (BLOCK_HEIGHT - nY - 1)] = g_pCurBlock[(nY * BLOCK_HEIGHT) + nX];
            }
        }

        memcpy_s(g_pCurBlock, nMemSize, nTemps, nMemSize);
    }

    return g_pCurBlock;
}

void DestroyGame()
{
    // 블럭 데이터 제거
    if (g_pCurBlock != nullptr)
    {
        delete[] g_pCurBlock;
        g_pCurBlock = nullptr;
    }

    if (g_console.hBuffer[0] != nullptr)
    {
        CloseHandle(g_console.hBuffer[0]);
    }

    if (g_console.hBuffer[1] != nullptr)
    {
        CloseHandle(g_console.hBuffer[1]);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역으로 블럭 데이터를 가지고 있을 포인터&lt;code&gt;g_pCurBlock&lt;/code&gt;를 선언 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 포인터는 &lt;code&gt;DestroyGame 함수&lt;/code&gt;에서 제거할 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;InitGame 함수&lt;/code&gt;에 플레이어(블럭)의 초기 값을 넣어줍시다.&lt;/p&gt;
&lt;pre id=&quot;code_1675944166210&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InitGame(bool bInitConsole = true)
{
    // 플레이어(블럭) 데이터 초기화
    {
        // START_POS_X = 4
        // START_POS_Y = 1
        g_player.SetPosition(START_POS_X, START_POS_Y);
        g_player.SetXPositionRange(-1, MAP_WIDTH);
        g_player.SetYPositionRange(0, MAP_HEIGHT);
        g_player.SetBlock(1);    // J 블럭
        g_player.SetDirection(CPlayer::eDirection::Dir0);
        g_player.SetGameScore(0);
        g_player.SetGameOver(false);
    }

    // 콘솔 데이터 초기화
    if (bInitConsole)
    {
        // 생략 ...
    }

    // 맵 데이터 초기화
    {
        int nMapSize = sizeof(int) * MAP_WIDTH * MAP_HEIGHT;
        memcpy_s(g_nArrMap, nMapSize, ORIGIN_MAP, nMapSize);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 메인 함수에 &lt;code&gt;InputKey 함수&lt;/code&gt;를 추가하고 실행하여봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1675944238711&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int main(void)
{
    InitGame();

    while (true)
    {
        // 키 입력 함수
        InputKey();
        CalcPlayer();

        Render(3, 1);

        ClearScreen();
        BufferFlip();
        Sleep(1);
    }

    DestroyGame();
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실행을 하면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/S0XoD/btrYLvfM6G5/pyXl5kMu79na2QJZuBtKtk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/S0XoD/btrYLvfM6G5/pyXl5kMu79na2QJZuBtKtk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/S0XoD/btrYLvfM6G5/pyXl5kMu79na2QJZuBtKtk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/S0XoD/btrYLvfM6G5/pyXl5kMu79na2QJZuBtKtk/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;251&quot; height=&quot;494&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 문제점은 2가지 입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;잔상이 남음&lt;/li&gt;
&lt;li&gt;Frame을 넘어서 그림이 그려짐&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 첫번째 문제를 해결하여 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;잔상이 남는 문제 해결&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 우리는 버퍼를 이용하여 새롭게 변경된 부분에만 그림을 그리고 있기 때문에 기존의 잔상이 남습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결 방법은 이전의 플레이어(블럭) 위치를 기억하여 위치를 변경할 때 마다 이전 위치를 Clear 시키고 현재 위치에 그림을 그리도록 하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷_20230209_091415.png&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcqUl8/btrYKvf23SR/PkQYZ8mHr1d07GyP4XkWz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcqUl8/btrYKvf23SR/PkQYZ8mHr1d07GyP4XkWz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcqUl8/btrYKvf23SR/PkQYZ8mHr1d07GyP4XkWz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcqUl8%2FbtrYKvf23SR%2FPkQYZ8mHr1d07GyP4XkWz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1021&quot; height=&quot;497&quot; data-filename=&quot;스크린샷_20230209_091415.png&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 위치를 기억하도록 하기 위한 플레이어(블럭) 객체를 하나 더 전역으로 선언합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675944963110&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 플레이어(블럭) 데이터 (전역 변수)
CPlayer g_player;
// 이전 위치를 기억할 플레이어(블럭) 데이터 (전역 변수)
CPlayer g_prevPlayerData;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;InitGame 함수&lt;/code&gt;에 이전 위치 기록용 플레이어(블럭) 데이터를 초기화 해줍시다.&lt;/p&gt;
&lt;pre id=&quot;code_1675945045192&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void InitGame(bool bInitConsole = true)
{
    // 플레이어(블럭) 데이터 초기화
    {
        // START_POS_X = 4
        // START_POS_Y = 1
        g_player.SetPosition(START_POS_X, START_POS_Y);
        g_player.SetXPositionRange(-1, MAP_WIDTH);
        g_player.SetYPositionRange(0, MAP_HEIGHT);
        g_player.SetBlock(1);    // J 블럭
        g_player.SetDirection(CPlayer::eDirection::Dir0);
        g_player.SetGameScore(0);
        g_player.SetGameOver(false);
        
        // 플레이어(블럭) 데이터를 이전 위치 기록용 데이터에 초기 데이터로 설정
        g_prevPlayerData = g_player;
    }

    // 생략 ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;code&gt;CalcPlayer 함수&lt;/code&gt;를 변경하여줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675945252191&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void CalcPlayer()
{
    COORD playerCursor = g_player.GetCursor();

    // 이전 위치의 블럭 제거 코드
    // (이전 위치과 현재 위치가 다른 경우)
    if (g_prevPlayerData != g_player)
    {
        // 이전 위치의 블럭데이터를 가져옴
        int* pBlock = GetRotateBlock(g_prevPlayerData.GetBlock(), g_prevPlayerData.GetDirection());
        COORD sprevCursor = g_prevPlayerData.GetCursor();

        for (int nY = 0; nY &amp;lt; BLOCK_HEIGHT; ++nY)
        {
            for (int nX = 0; nX &amp;lt; BLOCK_WIDTH; ++nX)
            {
                // 이전 위치의 블럭이 위치한 좌표의 데이터를 지워줌
                if (pBlock[(nY * BLOCK_HEIGHT) + nX] &amp;amp;&amp;amp;
                    pBlock[(nY * BLOCK_HEIGHT) + nX] == g_nArrMap[sprevCursor.Y + nY][sprevCursor.X + nX])
                    g_nArrMap[sprevCursor.Y + nY][sprevCursor.X + nX] = 0;
            }
        }

        // 현재 플레이어(블럭)의 정보를 이전 정보에 기록
        g_prevPlayerData = g_player;
    }

    int* pBlock = GetRotateBlock(g_player.GetBlock(), g_player.GetDirection());
    for (int nY = 0; nY &amp;lt; BLOCK_HEIGHT; ++nY)
    {
        for (int nX = 0; nX &amp;lt; BLOCK_WIDTH; ++nX)
        {
            if (pBlock[(nY * BLOCK_HEIGHT) + nX])
                g_nArrMap[playerCursor.Y + nY][playerCursor.X + nX] = pBlock[(nY * BLOCK_HEIGHT) + nX];
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 실행하여 봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tDS1W/btrYI4Xz1rS/VeVsQ3L36qFVLvzIDwDPj1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tDS1W/btrYI4Xz1rS/VeVsQ3L36qFVLvzIDwDPj1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tDS1W/btrYI4Xz1rS/VeVsQ3L36qFVLvzIDwDPj1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/tDS1W/btrYI4Xz1rS/VeVsQ3L36qFVLvzIDwDPj1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;502&quot; data-filename=&quot;2.gif&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Frame을 넘어서 그림이 그려지는 문제 해결&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 우리가 그림을 그리는 방식때문에 일어나는 현상입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷_20230209_092508.png&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DdGRX/btrYGuwe2iq/rTk34lJK3nKreFwqpK5Uy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DdGRX/btrYGuwe2iq/rTk34lJK3nKreFwqpK5Uy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DdGRX/btrYGuwe2iq/rTk34lJK3nKreFwqpK5Uy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDdGRX%2FbtrYGuwe2iq%2FrTk34lJK3nKreFwqpK5Uy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;718&quot; height=&quot;494&quot; data-filename=&quot;스크린샷_20230209_092508.png&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상황인 것이죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 해결하기 위해서는 &lt;code&gt;Render 함수&lt;/code&gt;를 변경하여야합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675948367088&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void Render(int nXOffset = 0, int nYOffset = 0)
{
    COORD coord{ 0, };
    int nXAdd = 0;
    DWORD dw = 0;

    for (int nY = 0; nY &amp;lt; MAP_HEIGHT; ++nY)
    {
        // 한 라인에 그려지는 블록의 개수
        int nBlockCount = 0;
        nXAdd = 0;

        for (int nX = 0; nX &amp;lt; MAP_WIDTH; ++nX)
        {
            coord.X = nXAdd + nXOffset;
            coord.Y = nY + nYOffset;

            SetConsoleCursorPosition(g_console.hBuffer[g_console.nCurBuffer], coord);
            WriteFile(g_console.hBuffer[g_console.nCurBuffer], BLOCK_TYPES[g_nArrMap[nY][nX]], sizeof(BLOCK_TYPES[g_nArrMap[nY][nX]]), &amp;amp;dw, NULL);

            // 1칸 증가
            ++nXAdd;

            // 공백의 경우에는 2칸이 1칸을 이룸(공백 2칸이 문자 한 칸과 같은 넓이를 이룸)
            if (g_nArrMap[nY][nX] == 0)
                ++nXAdd;
            // 블럭의 개수를 셈
            else
                ++nBlockCount;
        }

        // 벗어난 부분 덧칠하기            
        if (nY &amp;gt; 0 &amp;amp;&amp;amp;
            nY &amp;lt; MAP_HEIGHT - 1)
        {
            // 프레임이 끝나는 지점을 계산
            int nStart = nXOffset + nBlockCount + (MAP_WIDTH - nBlockCount) * 2;
            for (int nX = 0; nX &amp;lt; nBlockCount; ++nX)
            {
                coord.X = nStart + nX;
                SetConsoleCursorPosition(g_console.hBuffer[g_console.nCurBuffer], coord);
                WriteFile(g_console.hBuffer[g_console.nCurBuffer], BLOCK_TYPES[0], sizeof(BLOCK_TYPES[0]), &amp;amp;dw, NULL);
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실행을 해봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;3.gif&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPUEX9/btrYGtRGJeZ/OG62tpGxeXbKGrd7rAef2k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPUEX9/btrYGtRGJeZ/OG62tpGxeXbKGrd7rAef2k/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPUEX9/btrYGtRGJeZ/OG62tpGxeXbKGrd7rAef2k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bPUEX9/btrYGtRGJeZ/OG62tpGxeXbKGrd7rAef2k/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;502&quot; data-filename=&quot;3.gif&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 잔상도 제거되었고 Frame 외부에 그려지는 현상도 제거하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 플레이어(블럭)의 충돌 판정에 대해서 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현재 까지의 진행 프로젝트 다운로드&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/zL5OC/btrYJ1Gh3Wb/GpqIvIyx1mfNfNts6ykXj1/TetrisCpp.7z?attach=1&amp;amp;knm=tfile.7z&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;TetrisCpp.7z&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Study/C++</category>
      <category>C++</category>
      <category>Console</category>
      <category>Tetris</category>
      <category>도형</category>
      <category>움직이기</category>
      <category>이동</category>
      <category>출력</category>
      <category>콘솔</category>
      <category>테트리스</category>
      <author>Eskeptor</author>
      <guid isPermaLink="true">https://eskeptor.tistory.com/194</guid>
      <comments>https://eskeptor.tistory.com/194#entry194comment</comments>
      <pubDate>Thu, 9 Feb 2023 22:21:33 +0900</pubDate>
    </item>
  </channel>
</rss>