Skip to content
Permalink
Browse files

Open sourcing project for the world

  • Loading branch information...
ZohaibAhmed committed May 18, 2015
0 parents commit e67b8236165004789eff063703da1b090acb2349
@@ -0,0 +1,3 @@
{
"directory": "./tictactoe/static/bower_components"
}
@@ -0,0 +1,10 @@
*.DS_Store
*.pyc
.git

env

node_modules/
npm-debug.log
bower_components/
.module-cache
@@ -0,0 +1 @@
TicTacToe with Flask, Reactjs, Flux, and Redis
@@ -0,0 +1,19 @@
{
"name": "TicTacToe",
"version": "0.0.1",
"authors": [
"Zohaib Ahmed <zohaib@rocketfuse.com>"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.3.2",
"react": "~0.12.2"
}
}
@@ -0,0 +1,26 @@
'use strict';

// requirements
var gulp = require('gulp'),
browserify = require('gulp-browserify'),
size = require('gulp-size'),
clean = require('gulp-clean');


// tasks
gulp.task('transform', function () {
return gulp.src('./tictactoe/static/scripts/jsx/main.js')
.pipe(browserify({transform: ['reactify']}))
.pipe(gulp.dest('./tictactoe/static/scripts/js'))
.pipe(size());
});

gulp.task('clean', function () {
return gulp.src(['./tictactoe/static/scripts/js'], {read: false})
.pipe(clean());
});

gulp.task('default', ['clean'], function () {
gulp.start('transform');
gulp.watch('./tictactoe/static/scripts/jsx/main.js', ['transform']);
});
@@ -0,0 +1,24 @@
{
"name": "TicTacToe",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"bower": "^1.3.12",
"gulp": "^3.8.11",
"gulp-browserify": "^0.5.1",
"gulp-clean": "^0.3.1",
"gulp-size": "^1.2.1",
"react": "^0.12.2",
"reactify": "^1.0.0",
"underscore": "^1.8.2",
"superagent": "^0.21.0",
"flux": "^2.0.1",
"object-assign": "^1.0.0"
}
}
@@ -0,0 +1,7 @@
Flask==0.10.1
Jinja2==2.7.3
MarkupSafe==0.23
Werkzeug==0.10.1
itsdangerous==0.24
flask-redis
ujson==1.33
@@ -0,0 +1,2 @@
#!/bin/bash
python tictactoe/app.py
@@ -0,0 +1,124 @@
from flask import Flask, render_template, session, request
from flask.ext.redis import FlaskRedis
from tictactoe import TicTacToe
import uuid, random, json

app = Flask(__name__)
app.secret_key = "Thisismysecret"
store = FlaskRedis(app) # storing all the games

def is_gameOver(ttt):
'''
Check to see if the game is over
'''
if ttt.complete():
winner = ttt.winner()
if winner:
return winner
else:
return "TIE"

return None

def difference(current_session_board, player_board):
'''
Get the number of differences between the state that is saved and the state that is sent by the player
'''
differences = 0
for i in range(len(player_board)):
if current_session_board[i] != player_board[i]:
differences += 1

return differences

def enemy(player):
'''
Return the enemy player
'''
if player == 'x':
return 'o'
return 'x'

def determine_move(board, player):
'''
Given the board and the player, get the next move
'''
tmp = -2
moves = []
available = board.get_valid_moves()

if len(available) == 9:
return 4

for each_move in board.get_valid_moves():
board.set_move(each_move, player)
val = board.alpha_beta(board, board.enemy(player), -2, 2)
board.set_move(each_move, '')

if val > tmp:
tmp = val
moves = [each_move]
elif val == tmp:
moves.append(each_move)

return random.choice(moves)

@app.route('/')
def index():
# create a token for this game
token = str(uuid.uuid4())
session['uuid'] = token
board = ['', '', '', '', '', '', '', '', '']
# store the current state of the game in redis
store.lpush(uuid, *board)

return render_template('index.html')

@app.route('/newgame', methods=['GET'])
def newgame():
board = ['', '', '', '', '', '', '', '', '']
# Reset the current state to blank
store.delete(session['uuid'])
store.lpush(session['uuid'], *board)

return 'OK'

@app.route('/move', methods=['GET'])
def move():
# Get the current state of the game
current_state = store.lrange(session['uuid'], 0, -1)
current_state.reverse()

player_board = json.loads(request.args['board'])
player = request.args['player']

# find out if there are more than 1 differences in between the last state and this one
if difference(current_state, player_board) > 1:
return json.dumps({"status": "NOTVALID"}) # Prevent cheating

ai = enemy(player)
ttt = TicTacToe(player_board)

# Check to see if the game is over after the player made a move
gameover = is_gameOver(ttt)
if gameover:
return json.dumps({"status": "OVER", "winner": gameover})

move = determine_move(ttt, ai)
ttt.set_move(move, ai)

# Set the new state in the store
store.delete(session["uuid"])
store.lpush(session['uuid'], *ttt.get_board())

# check to see if the game is over after the AI made a move
gameover = is_gameOver(ttt)
if gameover:
return json.dumps({"status": "MOVE", "move": str(move), "gameover": True, "winner": gameover})

# Get the next move
return json.dumps({"status": "MOVE", "move": str(move), "gameover": False, "winner": None})

if __name__ == '__main__':
app.run(debug=True)

@@ -0,0 +1,56 @@
/* custom styles */

html, body {
height: 100%;
}

.title span {
font-weight: normal;
font-style: italic;
color: #EAEAEA;
}

.container {
text-align: center;
max-width: 630px;
}

input{
text-align: center;
border: 5px solid;
padding: 13px 12px;
font-size: 16px;
outline: none;
margin-bottom: 20px;
}

ul{
margin-left: 20px;
text-align: left;
}

.status-x {
background: #E9FF8D;
}
.status-o {
background: #A3CBFF;
}

#Game {
width: 600px;
height: 600px;
padding: 0;
margin-bottom: 20px;
float: left;
outline: 1px solid #b4b4b4;
}

#Game .tile {
width: 200px;
height: 200px;
outline: 1px solid #EAEAEA;
float: left;
line-height: 160px;
text-align: center;
font-size: 200px;
}

0 comments on commit e67b823

Please sign in to comment.
You can’t perform that action at this time.