https://murmuring-ocean-10847.herokuapp.com/
Install these in the environment if you don't have them already.
npm install
pip install Flask
pip install -r requirements.txt
pip install flask-socketio
pip install flask-cors
npm install -g heroku
(Not needed if you only want to run locally)pip install psycopg2-binary
pip install Flask-SQLAlchemy==2.1
- On
https://github.com/new
, create a new personal repository. Name it whatever you want. - In terminal, in your home directory, clone the repo:
https://github.com/NJIT-CS490-SP21/project2-as3627.git
. cd
into the repository that is created and you should see all the files.- Then, connect this cloned repo to your new personal repo made in Step 1:
git remote set-url origin https://www.github.com/{your-username}/{repo-name}
(be sure to change your username and repo-name and remove the curly braces) - Run
git push origin main
to push the local repo to remote. You should now see this same code in your personal repo.
- Run
echo "DANGEROUSLY_DISABLE_HOST_CHECK=true" > .env.development.local
in the project directory cd
intoreact-starter
directory, and runnpm install socket.io-client --save
These first steps are the general setup for databases.
- Install PostGreSQL:
sudo yum install postgresql postgresql-server postgresql-devel postgresql-contrib postgresql-docs
Enter yes to all prompts. - Initialize PSQL database:
sudo service postgresql initdb
- Start PSQL:
sudo service postgresql start
- Make a new superuser:
sudo -u postgres createuser --superuser $USER
If you get an error saying "could not change directory", that's okay! It worked! - Make a new database:
sudo -u postgres createdb $USER
If you get an error saying "could not change directory", that's okay! It worked! - Type
psql
- Type this with your username and password (DONT JUST COPY PASTE):
create user some_username_here superuser password 'some_unique_new_password_here';
e.g.create user namanaman superuser password 'mysecretpassword123';
- do
\q
to quit. - Save your username and password in a
sql.env
file with the formatSQL_USER=
andSQL_PASSWORD=
(Not in the directory, in your environment)
This next part is dealing with heroku databases.
- In your terminal, go to the directory with
app.py.
- Login and fill creds:
heroku login -i
- Create a new Heroku app (if you haven't already):
heroku create --buildpack heroku/python
- Create a new remote DB on your Heroku app:
heroku addons:create heroku-postgresql:hobby-dev
(If that doesn't work, add a-a {your-app-name}
to the end of the command, no braces) - See the config vars set by Heroku for you:
heroku config
. Copy paste the value for DATABASE_URL - Create a
.env
file and add set our var DATABASE_URL. Runtouch .env && echo "DATABASE_URL='copy-paste-database-url-here'" > .env
- In the terminal, run
python
to open up an interactive session. Let's initialize a new database in it using SQLAlchemy functions. Type in these Python lines one by one:
>> from app import db
>> import models
>> db.create_all()
- Note that if you don't do this, it can cause an issue with connecting to the DB, and can freeze up the game.
- You can sign up for a free Heroku account on their website here: https://signup.heroku.com/login.
- Heroku is used to host the web app.
- Run command in terminal (in your project directory):
python app.py
- Run command in another terminal,
cd
into the project directory, and runnpm run start
- Preview web page in browser
'/'
- Create a Heroku app (if you haven't already):
heroku create --buildpack heroku/python
- Add the nodejs buildpack:
heroku buildpacks:add --index 1 heroku/nodejs
- Push to Heroku:
git push heroku main
-
One known problem is that when a user disconnects (closes tab, window, etc.) the player list and spectators list will not remove them. This can cause a mjaor issue if one of the players disconnect, causing the game to be stuck waiting for a player who left to make a move. For the sake of milestone 1, we assumed no one leaves the game and that everyone connects before the first move is made, but this is still a ploblem that I have to acknowledge. One solution could be the use of pinging each client. Every minute or so, the server could send out a ping to check if the user is still connected, and if they leave, the player/spectator array could be updated. If a player client doesn't respond to the ping, we could restart the game and have the first spectator take over as a player.
-
Another known problem is that in order to create the db in the first place, you need to run:
$ python
>> from app import db
>> import models
>> db.create_all()
inside the command line first. The DB doesn't automatically create itself otherwise for some reason. I don't have any potential fix for this, so I recommend doing this when creating a new DB.
-
One future feature I'd like to implement is a timer condition. After making a move, each player should have a minute or so to respond with a move of their own. If the player does not respond within the time limit, they automatically forfeit. This could be done on the server side, with the back end checking the passage of time between moves, and emitting a forefit response to the client should time be up.
-
One other feature I would like to implement is a password field. This adds a level of security to the user account. We can have a password field in the Database and upon login, if the user exists, it would check the passwords and then confirm logging in. Currently, a user can log in as any created username and mess with their rankings. With the addition of the password field, it would no longer be possible.
-
Another feature I would like to implement is a match history field in the database. It would track the users past 5 games with a string of W's, L's, and even D's (Wins, Losses, Draws). For example, WLLDW. Upon the game ending, the oldest part of the string would get dropped and the latest match history would be added.
-
An issue I faced was that when a player logged in, their username wouldn't be put into the local players array until another user joined in after them. I believe this issue was caused becuase when the user logs in, the local players array wouldn't update until another
login
was emitted from the server. I needed to be ablt to emit the message to all clients including the one who logged in. I was able to fix this issue by looking over Stack Overflow. I found someone who had a similar issue and discovered the problem was in my python code, I hadinclude_self = False
when I was emitting. By changing theFalse
to aTrue
, I was able to update the players' array right away, without the need for another user to login. -
In my previous version of the code, if someone logged in with the same username as a player, they were able to make a move on the board when it came to be that player's turn. After this occured, I decided to only have unique usernames logged in at once. In order to do this, I decided to run a check during login. On the client side, it emits
login
when entering a username, and sends it to the server, and the server checks both players and spectators. If it finds a duplicate, it emits back adeny
. If it isn't a duplicate, it emits back aconfirm
. Inside theuseEffect
function, I was using the stateusername
as a comparision checker, but it didn't seem to work. After attempting to rewrite the function again, I found that theusername
state was undefined. I asked my friend Mervyn for help and he told me to useuseRef
s as references for the state variables. He encountered a similar issue and it was apparently due to howuseEffect
deals with state variables. With that change in my code, I was able to get it working. -
When I was trying to update the database for points, it wasn't commiting the changes. Initially my code was using
models.Player.query...
as the query string. I tried looking at stackOverflow and the documentation for SQLAlchemy, but that didn't help either. I tried askign one of my friends Philip and he ended up finding the issue with my code. Since I was usingmodels.Player.query...
as my query string, I was actually making a copy of the current db session. None of my changes were actually being done, they were only being printed out locally. I had to dodb.session.query...
in order to actually work with the database. -
When I was trying to send data from the backend to the front, I was initially using a dictionary for the usernames and their points. in the backend, all of the entries were ordered by points, but when I sent it to the front end, they were in alphabetical order by usernames. I initially assumed there was a problem with sending the data, but after I rewrote the functions, it was still arranging them wrong in the front end. I went to Stack Overflow, and I foudn that the issue was that in JS, apparently dictionaries were objects and that the keys can get rearranged when passing them from back to front. Due to this, I decided to use two lists instead of a dictioanry.
- The way I structured the program, I prevent two users from having the same username in the session.
- The restart game button works with a vote system. Both players have to hit the button to restart the game.
- After the first player logs in, they're taken to a waiting screen until the second player joins.