티스토리 뷰

C#

10 WPF

김윤지. 2023. 5. 11. 03:15

UniformGrid : Grid와 비슷하지만 포함되는 자식들의 높이나 너비가 똑같이 배치

 

007_UniformGrid (체스보드)

64개의 정사각형(UniformGrid)

<xaml 코드>

<Window x:Class="_007_UniformGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_007_UniformGrid"
        mc:Ignorable="d"
        Title="ChessBoard" Height="500" Width="500">
    <UniformGrid x:Name="chessBoard">
        
    </UniformGrid>
</Window>

500*500 크기의 chessBoard라는 이름의 UniformGrid 생성

 

<CS 코드>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace _007_UniformGrid
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            chessBoard.Rows = 8;        //chessBoard의 열을 8개로 나눈다
            chessBoard.Columns = 8;     //chessBoard의 행을 8개로 나눈다

            for (int i = 0; i < 64; i++)            //i(64)칸의 사각형
            {
                Rectangle r = new Rectangle();      //사각형 r을 그린다

                if ((i / 8) % 2 == 0)   //체스보드 행이 짝수이면 (i를 8로 나눈게 해당 사각형의 행 위치를 나타냄)
                {
                    if (i % 2 == 0)     //짝수행의 짝수칸
                        r.Fill = Brushes.Black;
                    else                //짝수행의 홀수칸
                        r.Fill = Brushes.Red;
                }

                else                    //체스보드 행이 홀수이면
                {
                    if (i % 2 == 0)
                        r.Fill = Brushes.Red;
                    else
                        r.Fill = Brushes.Black;
                }
                chessBoard.Children.Add(r);     //chessBoard의 자식으로 사각형 r
            }
        }
    }
}

 

008_MatchingGame

https://youtu.be/TiBVMJTLktI

<xaml 코드>

<Window x:Class="_008_MatchingGame.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_008_MatchingGame"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="500">
    <UniformGrid x:Name="board">
        
    </UniformGrid>
</Window>

500*500 크기의 board라는 이름의 UniformGrid 생성

 

<CS 코드>

프로그램이 시작될 때,

1) 16개 버튼을 만들어서 board에 넣는다

2) 랜덤하게 각 버튼에 숫자(0~7)을 배당한다

3) 이 숫자를 Button.Tag에 저장한다

4) 뒤집힌 그림으로 표시한다

Images 폴더를 생성해 그림을 추가한다

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;     //DispatcherTimer

namespace _008_MatchingGame
{
    public partial class MainWindow : Window
    {
        Random r = new Random();
        string[] icon = { "딸기", "레몬", "모과", "배", "사과", "수박", "파인애플", "포도" };
        int[] rnd = new int[16];

        Button first = null;
        Button second = null;
        
        // 타이머 사용 시 주의점
        // WinForm : Timer t = new timer();
        // WPF : DispatcherTimer t = new Dispatcher();

        DispatcherTimer myTimer = new DispatcherTimer();
        int matched = 0;        // 맞춘 카드의 숫자

        public MainWindow()
        {
            InitializeComponent();
            BoardSet();

            // 타이머 처리
            myTimer.Interval = new TimeSpan(0, 0, 0, 0, 750);  // 0.75초
            myTimer.Tick += MyTimer_Tick;
        }

        private void MyTimer_Tick(object sender, EventArgs e)
        {
            myTimer.Stop();
            first.Content = MakeImage("../../Images/check.png");
            second.Content = MakeImage("../../Images/check.png");
            first = null;
            second = null;
        }

        private void BoardSet()
        {
            for (int i = 0; i < 16; i++)
            {
                Button btn = new Button();
                btn.Background = Brushes.White;
                btn.Margin = new Thickness(10);
                btn.Tag = TagSet();
                btn.Content = MakeImage("../../Images/check.png");      // 폴더 위에 위에 ..
                btn.Click += Btn_Click;
                board.Children.Add(btn);
            }
        }

        private void Btn_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            string fruit = "../../Images/" + icon[(int)btn.Tag];
            btn.Content = MakeImage(fruit+".png");

            if (first == null)   // 지금 눌린 버튼이 첫번째 버튼이면
            {
                first = btn;
                btn.Content = MakeImage(fruit + ".png");
                return;
            }

            else if (second == null)
            {
                second = btn;
                btn.Content = MakeImage(fruit + ".png");
            }

            else
                return;

            // first와 second가 매치되는지를 체크(Tag로 체크)
            if((int)first.Tag == (int)second.Tag)
            {
                first = null;
                second = null;
                matched += 2;
                if (matched >= 16)
                {
                    MessageBoxResult result = MessageBox.Show("성공! 재도전?", "Clear!", MessageBoxButton.YesNo);
                    if (result == MessageBoxResult.Yes) // 처음부터 시작
                    {
                        // 1. rnd[] 초기화
                        ResetRnd();
                        // 2. board 초기화(board 안에 있는 Children을 삭제)
                        board.Children.Clear();
                        // 3. BoardSet()
                        BoardSet();
                        // 4. matched = 0 초기화
                        matched = 0;
                    }
                    else
                        Close();
                }
           
            }
            else // 버튼 그림 매치가 안 되면
                myTimer.Start();
        }

        //rnd 배열을 초기화 한다
        private void ResetRnd()
        {
            for (int i = 0; i < 16; i++)
            {
                rnd[i] = 0;
            }
        }

        // v로 넘어온 이미지 파일을 img 객체로 만들어서 리턴하는 메소드
        private Image MakeImage(string v)
        {
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.UriSource = new Uri(v, UriKind.Relative);
            bi.EndInit();

            Image img = new Image();
            img.Margin = new Thickness(10);
            img.Stretch = Stretch.Fill;
            img.Source = bi;

            return img;
        }

        //0~15까지의 숫자를 한번씩만 만들어 리턴, 예상 시험문제!!!***
        private int TagSet()
        {
            int i;

            while (true) 
            { 
                i = r.Next(16);
                if (rnd[i] == 0) //처음 이 숫자가 나왔다면
                {
                    rnd[i] = 1;
                    break;
                }
                
            }
            return (i % 8);     //0~7까지의 숫자 = 과일을 구분
        }
    }
}

BoardSet 함수 : 게임 시작 시 보드 세팅

 private void BoardSet()
        {
            for (int i = 0; i < 16; i++)
            {
                Button btn = new Button();
                btn.Background = Brushes.White;
                btn.Margin = new Thickness(10);
                btn.Tag = TagSet();
                btn.Content = MakeImage("../../Images/check.png");      // 폴더 위에 위에 ..
                btn.Click += Btn_Click;
                board.Children.Add(btn);
            }
        }

이미지 경로 : Image 폴더는 Debug 폴더 속 실행파일 위(bin) 위(008_MatchingGame) 폴더에 있음

 

TagSet 함수 (중요핵심!!) : 중복되지 않는 태그값 생성 > 과일 구분

private int TagSet()
        {
            int i;

            while (true) 
            { 
                i = r.Next(16);     //0~15의 숫자를 랜덤하게 생성
                if (rnd[i] == 0)    //i가 예전에 생성된 숫자인지 확인, rnd[i]가 0이라면 i가 처음이라는 뜻
                {
                    rnd[i] = 1;     //rnd[i]값을 1로 변경해 중복 방지
                    break;
                }
            }
            return (i % 8);     //0~7까지의 숫자 = 과일을 구분
        }

1. while 루프를 통해 적절한 태그 값을 찾을 때까지 반복
2. r.Next(16)를 사용하여 0부터 15까지의 숫자를 랜덤하게 생성
3. 생성된 숫자 i가 이전에 생성된 숫자인지 확인. 이를 위해 rnd 배열을 사용
4. rnd[i] 값이 0이라면 해당 숫자가 처음 나온 것이므로, rnd[i] 값을 1로 바꿈
5. while 루프를 종료하고, (i % 8) 값을 리턴. 이는 0부터 7까지의 숫자를 구분하여 과일을 표시하기 위함

 

즉, TagSet 함수는 중복되지 않는 태그 값을 생성하여 과일을 구분하는 데 사용되는 함수

`return (i % 8)`은 `TagSet` 함수에서 생성된 숫자를 0부터 7까지의 숫자로 변환하여 과일을 구분

`TagSet` 함수에서 생성된 `i` 값은 0부터 15까지의 범위를 가지는데, 이는 8개의 과일을 나타내기 위한 범위보다 크다

따라서 `(i % 8)` 연산을 통해 0부터 7까지의 숫자로 변환하여 각 과일을 구분

예를 들어, `i`가 0부터 7까지의 범위에 있을 때 `(i % 8)` 연산의 결과는 그대로 `i` 값과 동일하지만 `i`가 8 이상의 값일 때는 `(i % 8)` 연산을 통해 숫자가 0부터 7까지의 범위로 순환.

이렇게 변환된 숫자를 `icon` 배열의 인덱스로 사용하여 각 과일을 구분 가능

따라서 `return (i % 8)`은 `TagSet` 함수에서 생성된 숫자를 0부터 7까지의 숫자로 변환하여 과일을 구분하는 데 사용

Btn_Click 이벤트

 private void Btn_Click(object sender, RoutedEventArgs e)    //클래스 맨 앞에 1 2 버튼 선언 해줬음
        {
            Button btn = sender as Button;
            string fruit = "../../Images/" + icon[(int)btn.Tag];
            btn.Content = MakeImage(fruit+".png");

            if (first == null)   //지금 눌린 버튼이 첫번째 버튼이면
            {
                first = btn;
                btn.Content = MakeImage(fruit + ".png");
                return;
            }

            else if (second == null)
            {
                second = btn;
                btn.Content = MakeImage(fruit + ".png");
            }
            else
                return;

            // first와 second가 매치되는지를 체크(Tag로 체크)
            if((int)first.Tag == (int)second.Tag)
            {
                first = null;
                second = null;
                matched += 2;
                if (matched >= 16)
                {
                    MessageBoxResult result = MessageBox.Show("성공! 재도전?", "Clear!", MessageBoxButton.YesNo);
                    if (result == MessageBoxResult.Yes) // 처음부터 시작
                    {
                        // 1. rnd[] 초기화
                        ResetRnd();
                        // 2. board 초기화(board 안에 있는 Children을 삭제)
                        board.Children.Clear();
                        // 3. BoardSet()
                        BoardSet();
                        // 4. matched = 0 초기화
                        matched = 0;
                    }
                    else
                        Close();
                }
           
            }
            else // 버튼 그림 매치가 안 되면
                myTimer.Start();
        }

1. `Button btn = sender as Button;`: 클릭된 버튼을 `Button` 타입으로 형변환하여 `btn` 변수에 저장
2. `string fruit = "../../Images/" + icon[(int)btn.Tag];`: 클릭된 버튼의 태그를 사용해 `icon` 배열에서 과일 이미지 경로 가져오기
3. `btn.Content = MakeImage(fruit+".png");`: 클릭된 버튼 내용(Content)을 `MakeImage` 함수를 통해 과일 이미지로 설정
4. `if (first == null)`: 첫 번째 버튼이 선택되지 않은 경우
   - `first` 변수가 `null`인 경우에만 실행
   - `first` 변수에 `btn`을 저장하고, 버튼의 내용을 과일 이미지로 설정
   - `return;` 문을 통해 함수를 종료
5. `else if (second == null)`: 두 번째 버튼이 선택되지 않은 경우
   - `first` 변수가 이미 선택된 경우에 실행
   - `second` 변수가 `null`인 경우에만 실행
   - `second` 변수에 `btn`을 저장하고, 버튼의 내용을 과일 이미지로 설정
6. `else`: 첫 번째와 두 번째 버튼이 이미 선택된 경우 함수를 종료
7. `if ((int)first.Tag == (int)second.Tag)`: 첫 번째와 두 번째 버튼의 태그를 비교하여 매치되는지 확인
   - 태그가 매치되는 경우:
     - `first`와 `second` 변수를 `null`로 초기화
     - `matched` 변수를 2 증가
     - `matched` 값이 16 이상이 되면 모든 매치를 완료한 경우
       - 사용자에게 "성공! 재도전?"이라는 메시지 박스를 표시
       - 사용자의 선택에 따라 게임을 재시작하거나 종료
   - 태그가 매치되지 않는 경우:
     - `myTimer.Start();`를 호출하여 버튼의 이미지를 일정 시간 동안 보여준 후 다시 가리는 등의 처리 수행 가능

'C#' 카테고리의 다른 글

12 WPF SQL 설정 및 디자인  (0) 2023.05.17
11 SQL 설치  (0) 2023.05.17
9 WPF  (0) 2023.04.27
8 WPF  (0) 2023.04.26
7 TwoForms  (0) 2023.04.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함