Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.95/58: Рейтинг темы: голосов - 58, средняя оценка - 4.95
 Аватар для CyberAlfred
63 / 62 / 14
Регистрация: 16.12.2012
Сообщений: 606

Крестики-Нолики по сети

13.05.2013, 18:16. Показов 11104. Ответов 4

Студворк — интернет-сервис помощи студентам
День добрый. В двух словах есть лабораторная работа, суть которой создать игру "крестики-нолики" в которую могут играть два человека по сети. У каждого игрока программа может быть как сервером так и клиентом. для этого созданы две кнопки "Connect", "New server". Весь код чуть ниже, а ещё ниже сама лаба, вдруг кому пригодится. Беда в том, что, код переписанный из лабораторной работы не полностью функционирует, хотя список ошибок пуст. Жалуется на 267 строку, она же Server.Start();
Препода завалить таким вопросом не могу т.к. я заочник и ехать мне за 100км.
Кликните здесь для просмотра всего текста
C#
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
 
namespace lab3_1
{
    
 
    public partial class fMain : Form
    {
        PlayerType CheckWinner()
        {
            //перебираем все элементы массива 
            for (int i = 0; i < CellCount; i++)
            {
                for (int j = 0; j<CellCount; j++)
                {
                    //перебираем всех игроков, начиная с крестиков
                    for (PlayerType type = PlayerType.X; type <= PlayerType.O; type++)
                    {
                        //перебираем все направления по Ох
                        for (int goI = -1; goI <= 1; goI++)
                        {
                            //перебираем все направления по Оу
                            for (int goJ = -1; goJ <= 1; goJ++)
                            {
                                /*пропускаем вариант, когда goI & goJ =0
                                 * т.к. в этом случае мы никуда не двигаемся, а всегда находимся в текущей ячейке
                                */
                                if (goI == 0 && goJ == 0) continue;
                                //количество повротяющихся крестиков/ноликов
                                //зависит от type
                                int count = 0;
                                /*вызываем процедуру проверки непрерывной
                                 * последовательности фигуры игрока type
                                 * от ячейки [i, j] в направлении [goI, goJ]
                                 * после выполнения процедура должна заполнить
                                 * переменную count количеством найденных элементов*/
                                RecCheckWinner(i, j, goI, goJ, type, ref count);
                                //если кол-во элементов >= кол-ва необходимого
                                //для победы - возвращаем победителя
                                if (count >= CountToWin) return type;
                                
                            }
                        }
                    }
                }
            }
            //никто пока не победил
            return PlayerType.None;
        }
        public enum PlayerType
        {
            None,
            X,
            O
        }
        //Сервер. Может принимать входящие подключения.
        //После подключения нового клиента возращает объект класса TCPClient
        private TcpListener Server;
 
        //Удалённый клиент. Этот объект позволяет
        //принимать\отправлять информацию со стороны сервера.
        private TcpClient remoteClient;
 
        //локальный криент, который подключается к серверу.
        //этот объект позволяет принимать\отправлять информацию
        //со стороны клиента
        private TcpClient localClient;
 
        //игрок за которого вы играете
        //сервер - ркестик, клиент - нолик
        private PlayerType You = PlayerType.None;
 
        //пото к клиента
        private Thread thClient;
        //поток сервера
        private Thread thServer;
 
        //Игровое поле
        private Button[,] btnField;
        //Активный игрок
        //Внутренняя переменная, хранящая информацию об активном игроке
        private PlayerType innerActivePlayer = PlayerType.X;
        //Свойство ActivePlayer
        public PlayerType ActivePlayer
        {
            //метод, вызываемый при получении свойства ActivePlayer
            get
            {
                return innerActivePlayer;
            }
            //метод, вызываемый при установке свойства ActivePlayer
            set
            {
                //value - новое значение свойства
                innerActivePlayer = value;
 
                if (innerActivePlayer == PlayerType.X)
                    lblStatus.Text = "Ходят крестики";
                else
                    lblStatus.Text = "Ходят нолики";
            }
        }
        //Размер поля 
        private const int CellCount = 3;
        //Количество крестиков/ноликов в ряд для победы
        private const int CountToWin =3;
 
        public fMain()
        {
            InitializeComponent();
        }
 
        private void fMain_Load(object sender, EventArgs e)
        {
 
        }
 
        void Cleanup()
        {
            for (int i = 0; i < CellCount; i++)
            {
                for (int j = 0; j < CellCount; j++)
                {
                    btnField[i, j].Text = "";
                }
            }
        }
        //uint как int, только от 0 до 4,294,967,295
        uint X = 0;
        uint Y = 0;
        void btn_Click(object sender, EventArgs e)
        {
            //btn - кнопка на которую кликнули
            Button btn = (Button)sender;
            //если на кнопке пусто и текущий игрок это мы
            if (btn.Text == "" && You == ActivePlayer)
            {
                //выставляем на кнопке текст, равный ActivePlayer
                //при выхове метода ToString() элемент перечисления
                //будет преобразован в своё тестовое представление,
                //т.е. PlayerType.X будет равен Х
                btn.Text = ActivePlayer.ToString();
                //получаем координаты кнопки в массиве btnField
                //то что сохраняли в методе NEwGame
                string infoToSend = (string)btn.Tag;
                //преобразовываем строку в байтовый массив для передачи
                byte[] dataToSend = Encoding.Default.GetBytes(infoToSend);
                //усли мы являемся клиентов...
                if (localClient != null && localClient.Connected)
                {
                    //...то передаём данные (сервер их получает в потоке thServer)
                    localClient.GetStream().Write(dataToSend, 0, dataToSend.Length);
                }
                //если мыы являемся сервером...
                else if (remoteClient != null && remoteClient.Connected)
                {
                    //...то передаём данные (клиент их получает в потоке thCleint)
                    remoteClient.GetStream().Write(dataToSend, 0, dataToSend.Length);
 
                }
                //проверка победителя...
                PlayerType winner = CheckWinner();
                if (winner != PlayerType.None)
                {
                    if (winner == PlayerType.X)
                    {
                        X++;
                        lblX.Text = Convert.ToString(X);
                        MessageBox.Show("Выйграли крестики");
 
                    }
 
                    else
                    {
                        Y++;
                        lblY.Text = Convert.ToString(Y);
                        MessageBox.Show("Выйграли нолики");
                    }
 
                    Cleanup();
                    return;
                }
 
                if (ActivePlayer == PlayerType.X)
                    ActivePlayer = PlayerType.O;
                else
                    ActivePlayer = PlayerType.X;
            }
        }
 
        private void NewGame()
        {
            //Если массив не инициализирован
            if (btnField == null)
            {
                //выделяем память под массив,
                //размер массива задаётся константой CellCount
                btnField = new Button[CellCount, CellCount];
                //Прогоняем элементы
                for (int i = 0; i < CellCount; i++)
                {
                    for (int j = 0; j < CellCount; j++)
                    {
                        //Создаём новую кнопку
                        Button btn = new Button();
                        //Задаём ее координаты
                        btn.Left = 10 + i * 32;
                        btn.Top = 20 + j * 32;
                        btn.Width = 32;
                        btn.Height = 32;
                        //Сохраняем в свойстве Tag индексы кнопки в массиве btnField
                        btn.Tag = i.ToString() + " " + j.ToString();
                        //меняем шрифт кнопки на полужирный Arial размером 12
                        btn.Font = new Font("Arial", 6, FontStyle.Bold);
                        //Добавляем обработчик события Click
                        btn.Click += new EventHandler(btn_Click);
                        //добавляем кнопку в контейнер
                        grGameBox.Controls.Add(btn);
                        //и сохраняем в массиве
                        btnField[i, j] = btn;
 
                    }
 
                }
 
            }
            Cleanup();
        }
 
        void RecCheckWinner(int i, int j, int goI, int goJ, 
            PlayerType type, ref int count)
        {
            PlayerType CurType;
            //если I или j выходит за границы поля - выходим из процедуры без проверок
            if (i < 0 || i > btnField.GetLength(0) - 1) return;
            if (j < 0 || j > btnField.GetLength(1) - 1) return;
            //преобразуем текст в кнопке в элемент перечисления...
            //curType - элемент в ячейке[i,j]
            Enum.TryParse(btnField[i, j].Text, true, out CurType);
 
            //если элемент в ячейке [i, j] совпадает с type
            if (type == CurType)
            {
                //прибавляет количество совпадений
                count++;
                //вызываем рекурсивно эту же функцию, изменяя
                //текущие координаты на goI & goJ
                RecCheckWinner(i + goI, j + goJ, goI, goJ, type, ref count);
            }
        }
 
        private void btnConnect_Click(object sender, EventArgs e)
        {
            //ожидае подключений со всех адресов на порт 6785
            Server = new TcpListener(IPAddress.Any, 6785);
            //запускаем сервер
            Server.Start();
            //создаём новый поток (используем анонимную функцию и лямбда-выражение)
            thServer = new Thread(() =>
            {
                //далее идёт код потока, который будет выполняться паралельно...
 
                //ожидаем входящего подключения клиента (блокирующая операция)
                remoteClient = Server.AcceptTcpClient();
                byte[] buffer = new byte[1024];
                //клиент подключился - указываем, что мы играем крестиками
                You = PlayerType.O;
                //цикл выполняется до тех пор пока есть активное соединени
                while (remoteClient.Connected)
                {
                    //очищаем массив buffer (заполнем нулями)
                    Array.Clear(buffer, 0, buffer.Length);
                    //читаем ифнормацию клмента (блокирующая операция)
                    remoteClient.GetStream().Read(buffer, 0, 1024);
                    //получили новую информацию - переводим в строку
                    string strData = Encoding.Default.GetString(buffer);
                    //если сейчас ходят нолики (т.е. не мы)
                    if (ActivePlayer == PlayerType.X)
                    {
                        //разбиваем строку на массив элементов с разделителем пробелов
                        string[] ij = strData.Split(' ');
                        //получаем координаты кнопки на которую кликнул противник
                        int x = Convert.ToInt32(ij[0]);
                        int y = Convert.ToInt32(ij[1]);
 
                        //меняем у кнопки надпись на "X"
                        //т.к. этот компонент создан в другом потоке
                        //то его можно менять только через вызов метода Invoke.
                        //что не создавать доп.метод используем лямбда-выражения.
                        this.Invoke((Action)(() => { btnField[x, y].Text = "X"; }));
                        //удалённый игрок делает ход... меняем активного игрока
                        if (ActivePlayer == PlayerType.X)
                            ActivePlayer = PlayerType.O;
                        else
                            ActivePlayer = PlayerType.X;
 
                    }
                }
            });
            //Запускаем сервер
            thServer.Start();
            //отключаем панель создания сервера\подключения
            grNet.Enabled = false;
            //первыми ходят крестики
            ActivePlayer = PlayerType.X;
            //создаём игровое поле
            NewGame();
        }
 
        private void btnServer_Click(object sender, EventArgs e)
        {
            //ожидае подключений со всех адресов на порт 6785
            Server = new TcpListener(IPAddress.Any, 6785);
            //запускаем сервер
            Server.Start();
            //создаём новый поток (используем анонимную функцию и лямбда-выражение)
            thServer = new Thread(() =>
                {
                    //далее идёт код потока, который будет выполняться паралельно...
                    
                    //ожидаем входящего подключения клиента (блокирующая операция)
                    remoteClient = Server.AcceptTcpClient();
                    byte[] buffer = new byte[1024];
                    //клиент подключился - указываем, что мы играем крестиками
                    You = PlayerType.X;
                    //цикл выполняется до тех пор пока есть активное соединени
                    while (remoteClient.Connected)
                    {
                        //очищаем массив buffer (заполнем нулями)
                        Array.Clear(buffer, 0, buffer.Length);
                        //читаем ифнормацию клмента (блокирующая операция)
                        remoteClient.GetStream().Read(buffer, 0, 1024);
                        //получили новую информацию - переводим в строку
                        string strData = Encoding.Default.GetString(buffer);
                        //если сейчас ходят нолики (т.е. не мы)
                        if (ActivePlayer == PlayerType.O)
                        {
                            //разбиваем строку на массив элементов с разделителем пробелов
                            string[] ij = strData.Split(' ');
                            //получаем координаты кнопки на которую кликнул противник
                            int x = Convert.ToInt32(ij[0]);
                            int y = Convert.ToInt32(ij[1]);
 
                            //меняем у кнопки надпись на "0"
                            //т.к. этот компонент создан в другом потоке
                            //то его можно менять только через вызов метода Invoke.
                            //что не создавать доп.метод используем лямбда-выражения.
                            this.Invoke((Action)(() => { btnField[x, y].Text = "0"; }));
                            //удалённый игрок делает ход... меняем активного игрока
                            if (ActivePlayer == PlayerType.X)
                                ActivePlayer = PlayerType.O;
                            else
                                ActivePlayer = PlayerType.X;
 
                        }
                    }
                });
            //Запускаем сервер
            thServer.Start();
            //отключаем панель создания сервера\подключения
            grNet.Enabled = false;
            //первыми ходят крестики
            ActivePlayer = PlayerType.X;
            //создаём игровое поле
            NewGame();
        }
 
        private void fMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            //если сервер создан (!= null), nj - jcnfyfdkbdftv cthdth
            if (Server != null) Server.Stop();
            //закрываем подключение
            if (remoteClient != null && remoteClient.Connected) remoteClient.Close();
            if (localClient != null && localClient.Connected) localClient.Close();
        }
       
    }
}

Всем спасибо за помощь.
Вложения
Тип файла: rar lab3_1.rar (87.4 Кб, 649 просмотров)
2
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
13.05.2013, 18:16
Ответы с готовыми решениями:

Крестики-нолики по сети
Пишу курсовую на 3 курсе на тему крестики нолики по сети на C#. Всё уже готово только сервер не работает.Преподаватель помочь никак не...

Крестики-нолики
Добрый день, нужно срочно сдать супер мега крутой и в то же время на столько же не понятный для меня ПЯВ, а именно прогу на С# КРЕСТИКИ...

Крестики нолики
Помогите создать метод, который будет проверять победили крестики или нолики, только интересует как это сделать с помощью одномерного...

4
 Аватар для CyberAlfred
63 / 62 / 14
Регистрация: 16.12.2012
Сообщений: 606
15.05.2013, 07:15  [ТС]
P.S. Совсем забыл. после каждого запуска программы из папки debug в диспетчере задач глушите её руками. Почему то какой-то поток не закрывается сам, хотя опять же по лабе всё верно переписал.

Добавлено через 14 часов 45 минут
^^UP^^

Добавлено через 22 часа 12 минут
^^UP^^
1
0 / 0 / 0
Регистрация: 18.05.2015
Сообщений: 1
25.05.2015, 22:04
Сорри.

Добавлено через 19 секунд
Но мне

Добавлено через 14 секунд
нужен этот

Добавлено через 15 секунд
файл

Добавлено через 22 секунды
А для этого мне нужно 5 сообщений
0
Почетный модератор
 Аватар для Памирыч
23251 / 9163 / 1084
Регистрация: 11.04.2010
Сообщений: 11,014
27.05.2015, 15:02
Entis, чтобы скачать вложение, не нужно иметь 5 сообщений. Аттачи доступны уже после регистрации
0
0 / 0 / 0
Регистрация: 31.03.2018
Сообщений: 5
22.04.2018, 13:17
CyberAlfred, добрый день! Пишу курсовую по Вашему коду. Скажите, как запустить программу так, чтобы она работала по сети, не могу найти, как создать сервер. Заранее спасибо
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
22.04.2018, 13:17
Помогаю со студенческими работами здесь

Крестики-нолики
Решили вместе с друзьями учиться программировать. Решили написать игру крестики-нолики на поле NxN на C#. Но для начала решили сделать...

Крестики – нолики
Задача игры с участием двух игроков, например, крестики – нолики. Назовем игрока, проставляющего на игровой доске крестики, игроком x, а...

Крестики-нолики
Пишу игру- крестики нолики на большом поле. Естественно увеличивается кол-во фигур при выигрыше, алгоритм проверки сильно отличается от...

Крестики нолики 8х8
Помогите хотя бы немножечко. Буду очень благодарна Разработать программу, которая должна реализовать игру крестики-нолики 8х8. Область...

Не работают крестики-нолики
Доброго времени суток, помогите с проблемой, пожалуйста: мой код не работает, в чем проблема? Код (закомментированны функции, я думал,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru