I'm FanJae.

[Two Faced Poker] Day 1. 일부 기능 추가 및 Client 로직 개선 본문

Toy Project/Two Faced Poker

[Two Faced Poker] Day 1. 일부 기능 추가 및 Client 로직 개선

FanJae 2024. 10. 8. 23:51

1. Client 및 Server 정보

- 기본적인 서버는 이전에 구현했던 서버와  코드를 활용하였다.

- Github(Server)

- Github(Client)


2. 서버 정보 (게임 관련 필요 정보)

 

2-1. 게임에 필요한 기본적인 정보 추가

(foundation.h)

// 유저 이름과 승리 횟수 표기
class User
{
private:
	std::string name;
	int winCount;
	int chips;

public:
	User(std::string name, int winCount) : name(name), winCount(winCount), chips(0) { }

	std::string getName() const {
		return name;
	}
	int getwinCount() const {
		return winCount;
	}
};

// 카드의 앞면 뒷면
class Card
{
private:
	int front;
	int back;
public:
	Card(int front, int back) : front(front), back(back) { }

	int getFront() const {
		return front;
	}
	int getBack() const {
		return back;
	}
};

(deck.h & deck.cpp)

#pragma once
#include <algorithm>
#include <vector>
#include <random>
#include "foundation.h"
class Deck
{
private:
	std::vector<Card> cards;
public:
	Deck();

	void shuffleCard();
};

// deck.cpp
#include <random>
#include <chrono>
#include "deck.h"

Deck::Deck()
{
	for (int i = 1; i <= 10; i++)
	{
		for (int j = 1; j <= 10; j++)
		{
			if (i == j) continue; // 서로 앞 뒷면 서로 숫자
			cards.push_back(Card(i, j));
		}
	}
}

void Deck::shuffleCard()
{
	unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); // 현재 시각 기반 시드 생성
	std::shuffle(cards.begin(), cards.end(), std::default_random_engine(seed));
}

- 유저 정보에는 유저 ID와 현재까지의 승리 횟수 정보와 현재 칩 개수 정도를 두려한다.

- 이 게임에 특성에 맞게 카드에는 앞, 뒷면이 존재하며, 양면 숫자가 서로 다른 숫자로 이루어진 90장의 카드가 주어진다.

- 이를 섞는 기준은 현재 시간 기반으로 시드를 생성하도록 처리했다.

 

2-2. 로그인 추가 

void ClientEventHandler::Handle_Login()
{
	std::string send_message = "ID : Guest" + std::to_string(clientNumber);
	clientNumber++;
	send(socket, send_message.c_str(), send_message.length(), 0);
}

- 보통은 로그인 할때 DB에 저장을 하여 처리하는 것이 일반적이지만 DB를 사용하지 않았다.

- 임의로 첫번째 접속한 유저부터 Guest1과 같이 받도록 처리하였다.


3. Client 처리

 

3-1. 서버 연결 로직 개선

- 기존에는 사용자가 직접 IP와 Port를 입력하도록 처리하였지만, server.ini 폴더에 있는 값을 사용하도록 수정했다.

- 테스트를 할때마다 이를 입력하는 것이 번거롭기도 했고, 관리 편의성적 측면도 있다.

 

private void ConnectButton_Click(object sender, EventArgs e)
{
    string path = Constants.INI_FILE_PATH;
    string serverIp;
    int serverPort;

    (serverIp, serverPort) = Read_Server_Config(path);

    IPAddress Ip = IPAddress.Parse(serverIp);
    IPEndPoint endPoint = new IPEndPoint(Ip, serverPort);
    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    try
    {
        socket.Connect(endPoint);

        string request = Constants.LOGIN;
        byte[] buffer = Encoding.UTF8.GetBytes(request);
        socket.Send(buffer);

        byte[] recvBuffer = new byte[1024];
        int recvLength = socket.Receive(recvBuffer);

        string ID = Encoding.UTF8.GetString(recvBuffer, 0, recvLength);
        IDLabel.Text = ID;
        client_ID = ID.Substring("ID :".Length);

        MessageBox.Show("서버에 연결되었습니다.", "연결 성공", MessageBoxButtons.OK, MessageBoxIcon.Information);
        LogTextBox.Text += "[Log] 서버 연결을 성공하였습니다. \r\n";


    }
    catch (SocketException ex)
    {
        MessageBox.Show("서버에 연결할 수 없습니다: " + ex.Message, "연결 오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

private static (string, int) Read_Server_Config(string path)
{
    string serverIp = "";
    int serverPort = 0;

    try
    {
        string[] lines = File.ReadAllLines(path);
        foreach (string line in lines)
        {
            if (line.StartsWith("server="))
            {
                serverIp = line.Substring("server=".Length);
            }
            else if (line.StartsWith("port="))
            {
                serverPort = int.Parse(line.Substring("port=".Length));
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"server.ini 파일을 읽는 중 오류가 발생했습니다: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
        Environment.Exit(1); // 파일을 읽지 못하면 프로그램 종료
    }

    return (serverIp, serverPort);

- 기존 버튼을 이용해서 입력하는 방식보다는 조금 복잡해지만, 매번 입력하지 않아도 되는 장점이 존재한다.

 

3-2. 방 로직 개선 구상

- 오른쪽을 게임 판으로 사용하고자 한다. 구상은 다음과 같은 형태로 예상하고 있다.

 

3-3. 게임판 구상

① (손그림 버전...)

- 디자인은 원래 잘 못하니까라는 위안을 삼으며, 그래도 그럴듯하게 배치를 해본다.

② 구체화

- 항상 본인이 아래쪽이다. 카드의 앞면이 7, 뒷면이 3으로 상대는 앞면이 3이고 뒷면은 알 수 없다.

- 빨간 사각형은 배팅 상황을 표기한 것이고 오른쪽 가운데 부분은 자신의 턴에 맞게 베팅할때 사용할 것이다.


4. TODO

- 방 인원에 대한 로직 개선(2인 이상 들어가지 못하도록 처리 및 이미 다 찬 방은 검색이 되지 않게 개선)

- 게임 진행과 관련된 전반적인 Logic 설계 필요

 

Comments