본문 바로가기

C# WPF

C# 숫자퍼즐(Jeu De Tacquin) in WPF

Petzold 책에 나온 Jeu De Tacquin(숫자 퍼즐)을 버튼을 사용하여 만들어 보았습니다.

Grid를 이용했는데, Petzold 처럼 UniformGrid를 사용하는 것이 더 편할 수도 있겠습니다. 가장 기본적인 아이디어는 placement[4,4] 배열을 이용하여 버튼들을 관리하는 것입니다.

클릭할 때마다 Clear하고 다시 그리는 것이 좀 낭비스럽다는 생각이 드는데, 일단 동작은 합니다. 나중에 더 수정해야 될 부분입니다.

 

 

<Window x:Class="JeDeTacquin.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="50"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30">Jeu De Tacquin</TextBlock>
        <Line Stroke="LightSteelBlue" Grid.Row="0" VerticalAlignment="Bottom" X2="300"></Line>
        <Line Stroke="LightSteelBlue" Grid.Row="1" VerticalAlignment="Bottom" X2="300"></Line>
        <Button Name="btnShuffle" Grid.Row="1" Width="100" Height="30" Click="btnShuffle_Click">Shuffle</Button>
        <Grid Margin="0,1,0,0" Name="Board" Grid.Row="2">
        </Grid>
    </Grid>
</Window>

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 JeDeTacquin
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window
    {
        private int[,] placement = new int[4, 4];
        private bool isShuffled;    // 섞지 않고 끝내는 것을 방지

        public MainWindow()
        {
            InitializeComponent();

            BoardSet();     // Board setting
            initBoard();     // 초기화면
            DrawBoard();    // placement[,] 배열에 따라 버튼 삽입
        }

        private void BoardSet()
        {
            for (int i = 0; i < 4; i++)
            {
                RowDefinition row = new RowDefinition();
                Board.RowDefinitions.Add(row);
            }
            for (int i = 0; i < 4; i++)
            {
                ColumnDefinition col = new ColumnDefinition();
                Board.ColumnDefinitions.Add(col);
            }
        }

        private void initBoard()
        {
            for (int i = 0; i < 4; i++)
                for (int j = 0; j < 4; j++)
                    placement[i, j] = i * 4 + j + 1;
            placement[3, 3] = 0;
        }

        // 겹치지 않는 0~15까지의 랜덤 생성
        private void btnShuffle_Click(object sender, RoutedEventArgs e)
        {
            isShuffled = true;

            Board.Children.Clear();
            randomPlacement();

            DrawBoard();
        }
       
        private void randomPlacement()
        {
            int[] flag = new int[16];   // 0으로 초기화된다
            Random r = new Random();

            for (int row = 0; row < 4; row++)
            {
                for (int col = 0; col < 4; col++)
                {
                    int num = r.Next(16);
                    while (flag[num] != 0)
                        num = r.Next(16);
                    flag[num] = 1;
                    placement[row, col] = num;
                }
            }
        }

        private void DrawBoard()
        {
            for (int row = 0; row < 4; row++)
            {
                for (int col = 0; col < 4; col++)
                {
                    if (placement[row, col] != 0)
                    {
                        Button btn = new Button();
                        btn.Margin = new Thickness(1);
                        btn.FontSize = 15;
                        btn.FontWeight = FontWeights.Bold;
                        btn.Content = placement[row, col].ToString();
                        btn.Name = "btn" + row.ToString() + col.ToString();
                        btn.Click += btn_Click;
                        Board.Children.Add(btn);
                        Grid.SetRow(btn, row);
                        Grid.SetColumn(btn, col);
                    }
                }
            }
        }

        private void btn_Click(object sender, EventArgs e)
        {
            if (isShuffled == false)
            {
                MessageBox.Show("Press Shuffle Button First, before you Start the Game!");
                return;
            }

            Button btn = sender as Button;
            int eRow=-1, eCol=-1;   // Empty 좌표
            int row = Convert.ToInt32(btn.Name.Remove(0, 3)) / 10;
            int col = Convert.ToInt32(btn.Name.Remove(0, 3)) % 10;

            // 이웃한 공간을 검색
            if ( row-1 >= 0 && placement[row - 1, col] == 0)    // North
            { eRow = row - 1; eCol = col; }
            else if(row+1<=3 && placement[row+1, col] == 0) // South
            { eRow = row + 1; eCol = col; }
            else if (col+1 <=3 && placement[row, col+1] == 0)   // East
            { eRow = row; eCol = col + 1; }
            else if (col-1 >= 0 && placement[row, col - 1] == 0)    // West
            { eRow = row; eCol = col - 1; }

            // 이웃 공간에 빈칸이 없다. 끝
            if (eRow == -1)  return;

            // 이웃 공간에 빈칸이 있다 -> 클릭된 버튼을 빈칸으로 이동
            // 이 버튼의 좌표를 (x, y)에서 (emptyX, emptyY)로 이동
            btn.Name = "btn" + eRow.ToString() + eCol.ToString();
            placement[eRow, eCol] = placement[row, col];
            placement[row, col] = 0;

            Board.Children.Clear();
            DrawBoard();

            checkComplete();
        }

        private void checkComplete()
        {
            if (isShuffled == false)
                return;

            for (int i = 0; i < 4; i++)
                for (int j = 0; j < 4; j++)
                    if (placement[i, j] != i * 4 + j + 1)
                    {
                        if(i==3&&j==3)
                            MessageBox.Show("Congraturation!! You Completed!");
                        return;
                    }
        }
    }
}

 

BeeEye 드무