Noughts and Crosses using pygame and socket programming
Tags: hacktoberfest, opensource, python
Published: 2020-10-24 04:43:46


I participated in 'Ten Days Of Code' conducted by  GNU/Linux Users' Group, NIT Durgapur. The project was divided into 4 subtasks and for each subtask we could make a PR which was counted towards completing the Hacktoberfest Challenge. 

The problem statements regarding the tasks are here :
<a href="
https://drive.google.com/drive/u/0/folders/17IKIx3HlIeR6tP5N2IAPBQqFhtvywS1w">`https://drive.google.com/drive/u/0/folders/17IKIx3HlIeR6tP5N2IAPBQqFhtvywS1w`</a>

You can find my code according to the subtasks given here:
<a href="https://github.com/Debasmita-01/TDoC-Noughts-and-Crosses">`https://github.com/Debasmita-01/TDoC-Noughts-and-Crosses`</a>

In this blog I will be helping you to start with socket programming and finally build the multiplayer tic tac toe .However you should be having basic knowledge of `python`.

You can refer to the following video to learn the basics of python or brush up your memory.
<a href="https://www.youtube.com/watch?v=_uQrJ0TkZlc">`https://www.youtube.com/watch?v=_uQrJ0TkZlc`</a>

**For socket programming:**
<a href="https://www.youtube.com/playlist?list=PLhTjy8cBISErYuLZUvVOYsR1giva2payF">`https://www.youtube.com/playlist?list=PLhTjy8cBISErYuLZUvVOYsR1giva2payF`</a>
So after you watch these videos you are ready to start!
#####TASK 1:

*Problem Statement Ping-Pong Clients*

Make 2 client files which send data to each other using two different ports. One should send data (ex. "PING") and then receive some data (ex. "PONG"). While the other should first receive data and then send an appropriate response.

First initialize a socket connection and connect it to different network interfaces, for testing you can use the `same hostname: localhost` and different ports using `socket.gethostname()`. Sending data is done using `sendto()` method. It accepts as arguments, the data and the network interface address as a tuple containing hostname and port number. Receiving data is done using the `recv()`function; it needs a buffsize argument to denote the size of the data packet to be received. P.S Also do not forget to encode and decode the data. 

I made two files `ncserver.py` and `ncclient.py`.
``` python
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #making a socket instance and passed in two parameters
host='127.0.0.1'
port=12345 #reserving a port 
s.bind((host,port))
s.listen(5) # listening mode
```

So  I followed the usual order of methods:

1)`socket()`

2)`bind()`

3)`listen()`

4)`accept()`

### Resources you can check out:
1)<a href="https://docs.python.org/3/library/socket.html">https://docs.python.org/3/library/socket.html</a>

2)<a href="https://drive.google.com/file/d/17MDkLEWeBajEyqu-LzXZOhgxW9ZIUqv1/view?usp=sharing">https://drive.google.com/file/d/17MDkLEWeBajEyqu-LzXZOhgxW9ZIUqv1/view?usp=sharing</a>

3)<a href="https://drive.google.com/file/d/1jaNf0lfPFdChh5KhM1nAlCHPgy6wTrnQ/view?usp=sharing
">https://drive.google.com/file/d/1jaNf0lfPFdChh5KhM1nAlCHPgy6wTrnQ/view?usp=sharing</a>


#####TASK 2:
######Subtask-1

Let’s create our first client and server. We’ll begin with a simple implementation. The server will simply echo
whatever it receives back to the client.

######Subtask-2

Now in this part, the server will be handling more than 1 client simultaneously, which can be achieved by threading.

#####TO BE DONE :
Subtask-1 is fairly simple, almost similar to the first one except the fact that this time the server will echo whatever the client sends.

Subtask-2 is just an extension of Subtask-1.You should be having a basic knowledge of threading. You can check out <a href="https://realpython.com/intro-to-python-threading/">here</a> to brush up your concepts on threading.Now the main reason why threading is required is because when you handle one client you are receiving and sending data continuously which is basically an infinite loop. Now while this is going, normally the program will not be able to accept other clients, since its stuck in the loop. So, each connection to a client is threaded, and those thread will run simultaneously. Basically, because of one client(a thread) the other clients don't have to wait. That is the main reason why we need threads for this problem.

```python
import socket, threading
class ClientThread(threading.Thread):
    def __init__(self,clientAddress,clientsocket):
        threading.Thread.__init__(self)
        self.csocket = clientsocket
        print ("New connection added: ", clientAddress)
```
#####TASK-3:
*CLI BASED TIC-TAC-TOE*

<a href ="https://drive.google.com/file/d/1e21ZnkQWjPuKd1RP34fFvJ8d7bWEihC8/view">Problem statement task-3</a>

I hope that you are familiar with the rules of the tic-tac-toe game. `If not here you go`: 

GAME LOGIC :game completion logic check row-wise, column-wise and diagonally for matches also if total number of moves is 9 without a winner then the game would end in a draw.

Here you can go through my codes for <a href ="https://github.com/Debasmita-01/TDoC-Noughts-and-Crosses/blob/main/task3/tic_tac_toe_client.py">tic_tac_toe_client.py</a> and <a href="https://github.com/Debasmita-01/TDoC-Noughts-and-Crosses/blob/main/task3/tic_tac_toe_server.py">tic_tac_toe_server.py</a>
I have written comments beside each and every function which will help you understand the logic. You can do it without importing `re` module also.

```python 
#if the client has sent a quit message, then break out of the loop
			if(re.search("quit the game", client_move)):
				print(client_move)
				break
#else, convert the client's move to integer type
			else:
				client_move = int(client_move)
```

The `re` module offers a set of functions that allows us to search a string for a match:

| Function       | Description           |
| -------------  |:-------------:| 
| findall        | Returns a list containing all matches | 
| search         | Returns a Match object if there is a match anywhere in the string   |  
| split	         | Returns a list where the string has been split at each match     | 
|sub	         |Replaces one or many matches with a string|

For the client and server script its simple socket programming which we have done in the first two tasks.

#####TASK-4(The Final Task)

*Build the game interface using pygame and make it multiplayer with sockets.*

So I made three files here `servermain.py` , `clientmain.py` and `grid.py`.For the server side and the client side it are the usual things we have been doing so far.So lets concentrate on the new file grid.py.I have added comments beside each and every line of <a href="https://github.com/Debasmita-01/TDoC-Noughts-and-Crosses/tree/main/task4">my task 4 codes</a> so you can check out.


```python
import pygame
import os
```

I imported os for setting up the relative position of the window.


```python
os.environ['SDL_VIDEO_WINDOW_POS'] = '200,100'  #setting the relative position of the window
```

_This is how the grid will look like_


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5cy8gjpqhfla4vum31c4.png)

In my grid each cell is 200 X 200. You can set it up to any height and width according to your choice just remember to do the calculation accordingly. Whatever is your cell size put your image size `x.png`, `y.png` same.(in my case 200 pixels X 200 pixels)

######This is the way to link your images.

```python 
letterX = pygame.image.load(os.path.join('imgs', 'x.png')) # adding the images
letterO = pygame.image.load(os.path.join('imgs', 'o.png')) # adding the images
```

Finally import all the modules required in the main files.

```python
import pygame
from grid import Grid
import os
import threading
import socket
```
*FINAL LOOK*

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/krhorqiaoqgrkrqm3c7u.png)

#####LINK TO THE RESOURCES:
<a href="https://drive.google.com/file/d/183vlpHd2tKGp9nfLGCQ4DUPPfuSH_a8c/view?usp=sharing">https://drive.google.com/file/d/183vlpHd2tKGp9nfLGCQ4DUPPfuSH_a8c/view?usp=sharing</a>