diff --git a/backend/index.js b/backend/index.js index 2872ceb..61d3403 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,183 +1,289 @@ const app = require('express')() const http = require('http').createServer(app) -const io = require('socket.io')(http) -const config = require('./src/setup/config') -let rooms = [] -const createRoom = (roomId) => ({ - id: roomId, - users: [], - subscribers: [], - history: [], - turn: 'red', - end: false, -}) - -const createUser = (userId, userSocket) => ({ - id: userId, - name: '', - score: '', - room: '', - color: '', - isTurn: false, - role: '', - connection: false, - socket: userSocket, +const io = require('socket.io')(http, { + cors: { + origin: 'http://localhost:3000', + methods: ['GET', 'POST'], + }, }) - -const getRoom = (roomId) => { - const room = createRoom(roomId) +const config = require('./src/setup/config') +const rooms = [] +const users = [] +const createRoom = (roomId, socketId) => { + const room = { + id: roomId, + userIds: [], + subscriberIds: [], + history: {}, + turn: 'red', + isEnded: false, + socketIds: [socketId], + lastMove: {}, + } rooms.push(room) return room } -const findRoom = (roomId) => { - for (let i = 0; i < rooms.length; i++) - if (rooms[i].id === roomId) return rooms[i] - return false +const createUser = (userId, socketId) => { + const user = { + id: userId, + score: '', + roomIds: [], + color: '', + hasPermission: false, + role: '', + connection: false, + socketId, + } + users.push(user) + return user } -const searchBySocket = (socket, kind) => { - for (let i = 0; i < rooms.length; i++) - for (let j = 0; j < rooms[i].users.length; j++) - if (rooms[i].users[j].socket === socket) { - if (kind === 'user') return rooms[i].users[j] - else return rooms[i] - } - return false -} +// const getUserById = id => -const findUser = (room, userId) => { - for (let i = 0; i < room.users.length; i++) - if (room.users[i].id === userId) return room.users[i] - return false -} +const findRoomById = (roomId) => rooms.find((room) => room.id === roomId) +const findUserById = (userId, roomId) => + users.find((user) => { + const result = !!(user.id === userId && user.roomIds.includes(roomId)) + return result + }) -const configUser = (user, room, color, isTurn, role, connection, socket) => { - user.room = room +const findUserBySocketId = (socketId) => + users.find((user) => user.socketId === socketId) +const findRoomBySocketId = (socketId) => + rooms.find((room) => room.socketIds.includes(socketId)) + +const configUser = ({ + user, + room, + color, + hasPermission, + role, + connection, + socketId, +}) => { + user.roomIds.push(room.id) user.color = color - user.isTurn = isTurn + user.hasPermission = hasPermission user.role = role user.connection = connection - user.socket = socket + user.socketId = socketId } +const configRoom = {} + const hostFirstUser = (room, user, socket) => { - configUser(user, room, 'red', true, 'player', true, socket) + console.log( + `hosting first user with userId: ${user.id} in room with roomId: ${room.id}` + ) + configUser({ + user, + room, + color: 'red', + hasPermission: true, + role: 'player', + connection: true, + socketId: socket.id, + }) room.turn = 'red' - room.users.push(user) + room.userIds.push(user.id) + room.socketIds.push(socket.id) + socket.emit('hasPermission', user.hasPermission) socket.join(room.id) socket.emit('color', 'red') - socket.emit('wait', 'wait') + socket.emit('mustWait', true) } const hostSecondUser = (room, user, socket) => { - configUser(user, room, undefined, undefined, 'player', true, socket) - const secondUser = - room.users[0].id === user.id ? room.users[1] : room.users[0] + console.log( + `hosting second user with userId: ${user.id} in room with roomId: ${room.id}` + ) + + configUser({ + user, + room, + color: undefined, + hasPermission: false, + role: 'player', + connection: true, + socketId: socket.id, + }) + const secondUser = findUserById( + room.userIds[0] === user.id ? room.userIds[1] : room.userIds[0], + room.id + ) + console.log('roomTurn: ', room.turn) if (secondUser && secondUser.color === 'red') user.color = 'blue' else user.color = 'red' - if (room.turn !== user.color) user.isTurn = false - else user.isTurn = true - room.users.push(user) + user.hasPermission = room.turn === user.color + console.log('user has permission? ', user.hasPermission) + if (!room.userIds.includes(user.id)) room.userIds.push(user.id) + if (!room.socketIds.includes(socket.id)) room.socketIds.push(socket.id) + socket.emit('color', user.color) - socket.emit('permission', user.isTurn) + socket.emit('hasPermission', user.hasPermission) socket.emit('watch', room.history) - socket.broadcast.to(room.id).emit('wait', 'play') socket.join(room.id) + io.to(room.id).emit('mustWait', false) io.to(room.id).emit('introduce', 'hello') } const hostSubscriber = (room, user, socket) => { - configUser(user, room, undefined, undefined, 'subscriber', true, socket) - room.subscribers.push(user) + console.log( + `hosting subscriber with userId: ${user.id} in room with roomId: ${room.id}` + ) + configUser({ + user, + room, + color: undefined, + hasPermission: false, + role: 'subscriber', + connection: true, + socketId: socket.id, + }) + room.subscriberIds.push(user.id) socket.join(room.id) socket.emit('role', 'subscriber', room.turn) socket.emit('watch', room.history) } -const directToRoom = (roomId, userId, socket) => { - const room = findRoom(roomId) || getRoom(roomId) - const user = findUser(room, userId) || createUser(userId, socket) - switch (room.users.length) { - case 0: - hostFirstUser(room, user, socket) - break - case 1: - hostSecondUser(room, user, socket) - break - default: - if (findUser(room, userId)) hostSecondUser(room, user, socket) - else hostSubscriber(room, user, socket) - break +const directUserToRoom = (roomId, userId, socket) => { + const room = findRoomById(roomId) || createRoom(roomId, socket.id) + const user = findUserById(userId, roomId) || createUser(userId, socket.id) + if (room.userIds.includes(user.id)) { + console.log('direct to room', room, user) + socket.emit('warning', 'multiple device') + socket.disconnect(true) + } else { + switch (room.userIds.length) { + case 0: + hostFirstUser(room, user, socket) + break + case 1: + hostSecondUser(room, user, socket) + break + default: + if (!!findUserById(userId, roomId)) hostSecondUser(room, user, socket) + else hostSubscriber(room, user, socket) + break + } } } const checkValidation = (room, user, type) => { - const result = user.connection && !room.end && user.role === 'player' - if (type === 'change') - return user.isTurn && room.turn === user.color && result - else return !user.isTurn && room.turn !== user.color && result + const result = + user && room && user.connection && !room.end && user.role === 'player' + if (type === 'change') { + console.log( + `check validation user id: ${user.id} hasPermission is: ${user.hasPermission}` + ) + return user.hasPermission && room.turn === user.color && result + } else { + console.log( + `check validation user id: ${user.id}`, + !user.hasPermission, + room.turn !== user.color, + result + ) + return !user.hasPermission && room.turn !== user.color && result + } } -const changeTurn = (room) => { - if (room.turn === 'red') room.turn = 'blue' - else if (room.turn === 'blue') room.turn = 'red' - for (let i = 0; i < room.users.length; i++) - room.users[i].isTurn = !room.users[i].isTurn +const changeTurn = (room, userId) => { + if (room && room.turn === 'red') room.turn = 'blue' + else if (room && room.turn === 'blue') room.turn = 'red' + for (let i = 0; i < room.userIds.length; i++) { + const user = findUserById(room.userIds[i], room.id) + if (user.id === userId) user.hasPermission = false + else user.hasPermission = true + } return true } const check = (room, user, type) => { - if (checkValidation(room, user, type)) return changeTurn(room) + if (checkValidation(room, user, type)) return changeTurn(room, user.id) return false } io.on('connection', (socket) => { socket.emit('handshake', 'welcome! give me your room id!') - socket.on('handshake', (roomId, userId) => { - directToRoom(roomId, userId, socket) - }) - socket.on('introduce', (userId, roomId, name) => { - const room = findRoom(roomId) - const user = findUser(room, userId) - user.name = name - socket.broadcast.to(room.id).emit('name', name) + socket.on('handshake', (input) => { + const { roomId, userId } = input + directUserToRoom(roomId, userId, socket) }) + socket.on('introduce', (userId, roomId) => + socket.broadcast.to(roomId).emit('name', userId) + ) socket.on('disconnect', () => { - const room = searchBySocket(socket, 'room') - const user = searchBySocket(socket, 'user') - user.connection = false - if (user.role === 'player') - socket.broadcast.to(room.id).emit('wait', 'wait') + const user = findUserBySocketId(socket.id) + const room = findRoomBySocketId(socket.id) + console.log( + `user with ${user ? 'user' : 'socket'}id ${ + user ? user.id : socket.id + } disconnected` + ) + if (user) user.connection = false + if (user && user.role === 'player') { + room.userIds.splice(room.userIds.indexOf(user.id), 1) + socket.broadcast.to(room.id).emit('mustWait', true) + } }) - socket.on('change', (userId, roomId, change) => { - const room = findRoom(roomId) - const user = findUser(room, userId) + socket.on('change', (userId, roomId, line) => { + const room = findRoomById(roomId) + const user = findUserById(userId, roomId) + console.log('new line arrived: ', line) if (check(room, user, 'change')) { - change.color = user.color - room.history.push(change) - socket.broadcast.to(room.id).emit('change', change, user.color) + const { i, j, color } = line + line.color = user.color + room.lastMove = line + room.history[i] = { ...room.history[i] } + room.history[i][j] = color + socket.broadcast.to(room.id).emit('change', line, color) } else socket.emit('warning', 'warning') }) + socket.on('bouns', (roomId, userId, bouns) => { + const room = findRoomById(roomId) + const user = findUserById(userId, roomId) + if (user && user.color === bouns.color) { + const { i, j, color } = bouns + if (room.history[i] && room.history[i][j]) { + } else { + console.log(`new bouns arrived:`, bouns, `from user:`, user.id) + room.history[i] = { ...room.history[i] } + room.history[i][j] = color + + // sending gift! + if (room) room.turn = user.color + for (let i = 0; i < room.userIds.length; i++) { + const user = findUserById(room.userIds[i], room.id) + if (user.id === userId) user.hasPermission = true + else user.hasPermission = false + } + io.to(roomId).emit('gift', userId) + } + } + }) socket.on('gift', (userId, roomId) => { - const room = findRoom(roomId) - const user = findUser(room, userId) + const room = findRoomById(roomId) + const user = findUserById(userId, roomId) + console.log('new gift request arrived by user id:', userId) + if (check(room, user, 'gift')) io.to(room.id).emit('gift') else socket.emit('warning', 'warning') }) socket.on('resign', (userId, roomId) => { - const room = findRoom(roomId) - const user = findRoom(room, userId) + const room = findRoomById(roomId) + const user = findUserById(userId, roomId) room.end = true user.connection = false socket.broadcast.to(room.id).emit('resign', 'salam') }) socket.on('getname', (roomId) => { - const room = findRoom(roomId) + const room = findRoomById(roomId) let redName, blueName - for (let i = 0; i < room.users.length; i++) { - const element = room.users[i] + for (let i = 0; i < room.userIds.length; i++) { + const element = room.userIds[i] if (element.color === 'red') redName = element.name else blueName = element.name } @@ -185,7 +291,7 @@ io.on('connection', (socket) => { }) socket.on('message', (roomId, message) => { - const room = findRoom(roomId) + const room = findRoomById(roomId) socket.broadcast.to(room.id).emit('message', message) }) }) diff --git a/server/package.json b/backend/package.json similarity index 100% rename from server/package.json rename to backend/package.json diff --git a/backend/src/setup/config.js b/backend/src/setup/config.js index 3e1264b..862877c 100644 --- a/backend/src/setup/config.js +++ b/backend/src/setup/config.js @@ -6,14 +6,14 @@ const production = process.env.NODE_ENV === 'production' const defaultConfig = { server: { host: production ? 'localhost' : undefined, // all IPs - port: 3000, + port: 13797, }, } const getLocalConfig = () => { try { const config = fse.readJsonSync(process.env.WEBLITE_CONFIG_PATH)[ - 'نقطه‌بازی' + 'dots-and-boxes' ] if (!R.is(Object, config) || R.is(Array, config)) throw new TypeError() return config diff --git a/server/yarn.lock b/backend/yarn.lock similarity index 100% rename from server/yarn.lock rename to backend/yarn.lock diff --git a/frontend/7475741651600002657.svg b/frontend/7475741651600002657.svg deleted file mode 100644 index 4e9fcf8..0000000 --- a/frontend/7475741651600002657.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/GameAnalytics.js b/frontend/GameAnalytics.js deleted file mode 100644 index e8a3714..0000000 --- a/frontend/GameAnalytics.js +++ /dev/null @@ -1,5 +0,0 @@ -(function(scope){ -var CryptoJS=CryptoJS||function(o){function t(){}var e={},n=e.lib={},i=n.Base={extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),(n.init.prototype=n).$super=this,n},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var n in e)e.hasOwnProperty(n)&&(this[n]=e[n]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}},u=n.WordArray=i.extend({init:function(e,n){e=this.words=e||[],this.sigBytes=null!=n?n:4*e.length},toString:function(e){return(e||s).stringify(this)},concat:function(e){var n=this.words,t=e.words,i=this.sigBytes;if(e=e.sigBytes,this.clamp(),i%4)for(var r=0;r>>2]|=(t[r>>>2]>>>24-r%4*8&255)<<24-(i+r)%4*8;else if(65535>>2]=t[r>>>2];else n.push.apply(n,t);return this.sigBytes+=e,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=o.ceil(n/4)},clone:function(){var e=i.clone.call(this);return e.words=this.words.slice(0),e},random:function(e){for(var n=[],t=0;t>>2]>>>24-i%4*8&255;t.push((r>>>4).toString(16)),t.push((15&r).toString(16))}return t.join("")},parse:function(e){for(var n=e.length,t=[],i=0;i>>3]|=parseInt(e.substr(i,2),16)<<24-i%8*4;return new u.init(t,n/2)}},a=r.Latin1={stringify:function(e){var n=e.words;e=e.sigBytes;for(var t=[],i=0;i>>2]>>>24-i%4*8&255));return t.join("")},parse:function(e){for(var n=e.length,t=[],i=0;i>>2]|=(255&e.charCodeAt(i))<<24-i%4*8;return new u.init(t,n)}},d=r.Utf8={stringify:function(e){try{return decodeURIComponent(escape(a.stringify(e)))}catch(e){throw Error("Malformed UTF-8 data")}},parse:function(e){return a.parse(unescape(encodeURIComponent(e)))}},c=n.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new u.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=d.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(e){var n=this._data,t=n.words,i=n.sigBytes,r=this.blockSize,s=i/(4*r);if(e=(s=e?o.ceil(s):o.max((0|s)-this._minBufferSize,0))*r,i=o.min(4*e,i),e){for(var a=0;a>>7)^(v<<14|v>>>18)^v>>>3)+m[l-7]+((g<<15|g>>>17)^(g<<13|g>>>19)^g>>>10)+m[l-16]}v=c+((o<<26|o>>>6)^(o<<21|o>>>11)^(o<<7|o>>>25))+(o&u^~o&d)+f[l]+m[l],g=((i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22))+(i&r^i&s^r&s),c=d,d=u,u=o,o=a+v|0,a=s,s=r,r=i,i=v+g|0}t[0]=t[0]+i|0,t[1]=t[1]+r|0,t[2]=t[2]+s|0,t[3]=t[3]+a|0,t[4]=t[4]+o|0,t[5]=t[5]+u|0,t[6]=t[6]+d|0,t[7]=t[7]+c|0},_doFinalize:function(){var e=this._data,n=e.words,t=8*this._nDataBytes,i=8*e.sigBytes;return n[i>>>5]|=128<<24-i%32,n[14+(64+i>>>9<<4)]=r.floor(t/4294967296),n[15+(64+i>>>9<<4)]=t,e.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var e=i.clone.call(this);return e._hash=this._hash.clone(),e}});n.SHA256=i._createHelper(s),n.HmacSHA256=i._createHmacHelper(s)}(Math),function(){var d=CryptoJS.enc.Utf8;CryptoJS.algo.HMAC=CryptoJS.lib.Base.extend({init:function(e,n){e=this._hasher=new e.init,"string"==typeof n&&(n=d.parse(n));var t=e.blockSize,i=4*t;n.sigBytes>i&&(n=e.finalize(n)),n.clamp();for(var r=this._oKey=n.clone(),s=this._iKey=n.clone(),a=r.words,o=s.words,u=0;u>>2]>>>24-r%4*8&255)<<16|(n[r+1>>>2]>>>24-(r+1)%4*8&255)<<8|n[r+2>>>2]>>>24-(r+2)%4*8&255,a=0;a<4&&r+.75*a>>6*(3-a)&63));if(n=i.charAt(64))for(;e.length%4;)e.push(n);return e.join("")},parse:function(e){var n=e.length,t=this._map;!(i=t.charAt(64))||-1!=(i=e.indexOf(i))&&(n=i);for(var i=[],r=0,s=0;s>>6-s%4*2;i[r>>>2]|=(a|o)<<24-r%4*8,r++}return u.create(i,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}(),function(e){var n,t,i,r,s,a,o,u,d,c;(n=e.EGAErrorSeverity||(e.EGAErrorSeverity={}))[n.Undefined=0]="Undefined",n[n.Debug=1]="Debug",n[n.Info=2]="Info",n[n.Warning=3]="Warning",n[n.Error=4]="Error",n[n.Critical=5]="Critical",(t=e.EGAProgressionStatus||(e.EGAProgressionStatus={}))[t.Undefined=0]="Undefined",t[t.Start=1]="Start",t[t.Complete=2]="Complete",t[t.Fail=3]="Fail",(i=e.EGAResourceFlowType||(e.EGAResourceFlowType={}))[i.Undefined=0]="Undefined",i[i.Source=1]="Source",i[i.Sink=2]="Sink",r=e.http||(e.http={}),(s=r.EGAHTTPApiResponse||(r.EGAHTTPApiResponse={}))[s.NoResponse=0]="NoResponse",s[s.BadResponse=1]="BadResponse",s[s.RequestTimeout=2]="RequestTimeout",s[s.JsonEncodeFailed=3]="JsonEncodeFailed",s[s.JsonDecodeFailed=4]="JsonDecodeFailed",s[s.InternalServerError=5]="InternalServerError",s[s.BadRequest=6]="BadRequest",s[s.Unauthorized=7]="Unauthorized",s[s.UnknownResponseCode=8]="UnknownResponseCode",s[s.Ok=9]="Ok",s[s.Created=10]="Created",a=e.events||(e.events={}),(o=a.EGASdkErrorCategory||(a.EGASdkErrorCategory={}))[o.Undefined=0]="Undefined",o[o.EventValidation=1]="EventValidation",o[o.Database=2]="Database",o[o.Init=3]="Init",o[o.Http=4]="Http",o[o.Json=5]="Json",(u=a.EGASdkErrorArea||(a.EGASdkErrorArea={}))[u.Undefined=0]="Undefined",u[u.BusinessEvent=1]="BusinessEvent",u[u.ResourceEvent=2]="ResourceEvent",u[u.ProgressionEvent=3]="ProgressionEvent",u[u.DesignEvent=4]="DesignEvent",u[u.ErrorEvent=5]="ErrorEvent",u[u.InitHttp=9]="InitHttp",u[u.EventsHttp=10]="EventsHttp",u[u.ProcessEvents=11]="ProcessEvents",u[u.AddEventsToStore=12]="AddEventsToStore",(d=a.EGASdkErrorAction||(a.EGASdkErrorAction={}))[d.Undefined=0]="Undefined",d[d.InvalidCurrency=1]="InvalidCurrency",d[d.InvalidShortString=2]="InvalidShortString",d[d.InvalidEventPartLength=3]="InvalidEventPartLength",d[d.InvalidEventPartCharacters=4]="InvalidEventPartCharacters",d[d.InvalidStore=5]="InvalidStore",d[d.InvalidFlowType=6]="InvalidFlowType",d[d.StringEmptyOrNull=7]="StringEmptyOrNull",d[d.NotFoundInAvailableCurrencies=8]="NotFoundInAvailableCurrencies",d[d.InvalidAmount=9]="InvalidAmount",d[d.NotFoundInAvailableItemTypes=10]="NotFoundInAvailableItemTypes",d[d.WrongProgressionOrder=11]="WrongProgressionOrder",d[d.InvalidEventIdLength=12]="InvalidEventIdLength",d[d.InvalidEventIdCharacters=13]="InvalidEventIdCharacters",d[d.InvalidProgressionStatus=15]="InvalidProgressionStatus",d[d.InvalidSeverity=16]="InvalidSeverity",d[d.InvalidLongString=17]="InvalidLongString",d[d.DatabaseTooLarge=18]="DatabaseTooLarge",d[d.DatabaseOpenOrCreate=19]="DatabaseOpenOrCreate",d[d.JsonError=25]="JsonError",d[d.FailHttpJsonDecode=29]="FailHttpJsonDecode",d[d.FailHttpJsonEncode=30]="FailHttpJsonEncode",(c=a.EGASdkErrorParameter||(a.EGASdkErrorParameter={}))[c.Undefined=0]="Undefined",c[c.Currency=1]="Currency",c[c.CartType=2]="CartType",c[c.ItemType=3]="ItemType",c[c.ItemId=4]="ItemId",c[c.Store=5]="Store",c[c.FlowType=6]="FlowType",c[c.Amount=7]="Amount",c[c.Progression01=8]="Progression01",c[c.Progression02=9]="Progression02",c[c.Progression03=10]="Progression03",c[c.EventId=11]="EventId",c[c.ProgressionStatus=12]="ProgressionStatus",c[c.Severity=13]="Severity",c[c.Message=14]="Message"}(gameanalytics=gameanalytics||{});var gameanalytics,EGAErrorSeverity=gameanalytics.EGAErrorSeverity,EGAProgressionStatus=gameanalytics.EGAProgressionStatus,EGAResourceFlowType=gameanalytics.EGAResourceFlowType;!function(e){!function(e){var t,n;(n=t=t||{})[n.Error=0]="Error",n[n.Warning=1]="Warning",n[n.Info=2]="Info",n[n.Debug=3]="Debug";var i=(r.setInfoLog=function(e){r.instance.infoLogEnabled=e},r.setVerboseLog=function(e){r.instance.infoLogVerboseEnabled=e},r.i=function(e){if(r.instance.infoLogEnabled){var n="Info/"+r.Tag+": "+e;r.instance.sendNotificationMessage(n,t.Info)}},r.w=function(e){var n="Warning/"+r.Tag+": "+e;r.instance.sendNotificationMessage(n,t.Warning)},r.e=function(e){var n="Error/"+r.Tag+": "+e;r.instance.sendNotificationMessage(n,t.Error)},r.ii=function(e){if(r.instance.infoLogVerboseEnabled){var n="Verbose/"+r.Tag+": "+e;r.instance.sendNotificationMessage(n,t.Info)}},r.d=function(e){if(r.debugEnabled){var n="Debug/"+r.Tag+": "+e;r.instance.sendNotificationMessage(n,t.Debug)}},r.prototype.sendNotificationMessage=function(e,n){switch(n){case t.Error:console.error(e);break;case t.Warning:console.warn(e);break;case t.Debug:"function"==typeof console.debug?console.debug(e):console.log(e);break;case t.Info:console.log(e)}},r.instance=new r,r.Tag="GameAnalytics",r);function r(){r.debugEnabled=!1}e.GALogger=i}(e.logging||(e.logging={}))}(gameanalytics=gameanalytics||{}),function(e){var n,d,t;function c(){}n=e.utilities||(e.utilities={}),d=e.logging.GALogger,c.getHmac=function(e,n){var t=CryptoJS.HmacSHA256(n,e);return CryptoJS.enc.Base64.stringify(t)},c.stringMatch=function(e,n){return!(!e||!n)&&n.test(e)},c.joinStringArray=function(e,n){for(var t="",i=0,r=e.length;i>2,r=(3&n)<<4|(t=e.charCodeAt(d++))>>4,s=(15&t)<<2|(o=e.charCodeAt(d++))>>6,u=63&o,isNaN(t)?s=u=64:isNaN(o)&&(u=64),a=a+c.keyStr.charAt(i)+c.keyStr.charAt(r)+c.keyStr.charAt(s)+c.keyStr.charAt(u),n=t=o=0,i=r=s=u=0,de)return u.w(s+" validation failed: array cannot exceed "+e+" values. It has "+r.length+" values."),!1;for(var a=0;av.MaxNumberOfEntries},v.select=function(e,n,t,i){void 0===n&&(n=[]),void 0===t&&(t=!1),void 0===i&&(i=0);var r=v.getStore(e);if(!r)return null;for(var s=[],a=0;ai&&(s=s.slice(0,i+1)),s},v.update=function(e,n,t){void 0===t&&(t=[]);var i=v.getStore(e);if(!i)return!1;for(var r=0;r=d.MaxCount)){var s=o.getHmac(i,t),a=new XMLHttpRequest;a.onreadystatechange=function(){if(4===a.readyState){if(!a.responseText)return;if(200!=a.status)return void u.w("sdk error failed. response code not 200. status code: "+a.status+", description: "+a.statusText+", body: "+a.responseText);d.countMap[n]=d.countMap[n]+1}},a.open("POST",e,!0),a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("Authorization",s);try{a.send(t)}catch(e){console.error(e)}}},d.MaxCount=10,d.countMap={},d.timestampMap={},t=d,n.SdkErrorTask=t}(gameanalytics=gameanalytics||{}),function(e){var c,E,S,l,h,y,v,g,f,m,n;function A(){this.protocol="https",this.hostName="api.gameanalytics.com",this.version="v2",this.remoteConfigsVersion="v1",this.baseUrl=this.protocol+"://"+this.hostName+"/"+this.version,this.remoteConfigsBaseUrl=this.protocol+"://"+this.hostName+"/remote_configs/"+this.remoteConfigsVersion,this.initializeUrlPath="init",this.eventsUrlPath="events",this.useGzip=!1}c=e.http||(e.http={}),E=e.state.GAState,S=e.logging.GALogger,l=e.utilities.GAUtilities,h=e.validators.GAValidator,y=e.tasks.SdkErrorTask,v=e.events.EGASdkErrorCategory,g=e.events.EGASdkErrorArea,f=e.events.EGASdkErrorAction,m=e.events.EGASdkErrorParameter,A.prototype.requestInit=function(e,n){var t=E.getGameKey(),i=this.remoteConfigsBaseUrl+"/"+this.initializeUrlPath+"?game_key="+t+"&interval_seconds=0&configs_hash="+e,r=E.getInitAnnotations(),s=JSON.stringify(r);if(s){var a=this.createPayloadData(s,this.useGzip),o=[];o.push(s),A.sendRequest(i,a,o,this.useGzip,A.initRequestCallback,n)}else n(c.EGAHTTPApiResponse.JsonEncodeFailed,null)},A.prototype.sendEventsInArray=function(e,n,t){if(0!=e.length){var i=E.getGameKey(),r=this.baseUrl+"/"+i+"/"+this.eventsUrlPath,s=JSON.stringify(e);if(s){var a=this.createPayloadData(s,this.useGzip),o=[];o.push(s),o.push(n),o.push(e.length.toString()),A.sendRequest(r,a,o,this.useGzip,A.sendEventInArrayRequestCallback,t)}else t(c.EGAHTTPApiResponse.JsonEncodeFailed,null,n,e.length)}},A.prototype.sendSdkErrorEvent=function(e,n,t,i,r,s,a){if(E.isEventSubmissionEnabled()&&h.validateSdkErrorEvent(s,a,e,n,t)){var o,u=this.baseUrl+"/"+s+"/"+this.eventsUrlPath,d="",c=E.getSdkErrorEventAnnotations(),l=A.sdkErrorCategoryString(e);d+=c.error_category=l;var v=A.sdkErrorAreaString(n);d+=":"+(c.error_area=v);var g=A.sdkErrorActionString(t);c.error_action=g;var f=A.sdkErrorParameterString(i);if(0A.MAX_ERROR_MESSAGE_LENGTH&&(m=r.substring(0,A.MAX_ERROR_MESSAGE_LENGTH)),c.reason=m}var p=[];p.push(c),(o=JSON.stringify(p))?y.execute(u,d,o,a):S.w("sendSdkErrorEvent: JSON encoding failed.")}},A.sendEventInArrayRequestCallback=function(e,n,t,i){void 0===i&&(i=null),i[0],i[1];var r,s,a=i[2],o=parseInt(i[3]);r=e.responseText,s=e.status;var u=A.instance.processRequestResponse(s,e.statusText,r,"Events");if(u==c.EGAHTTPApiResponse.Ok||u==c.EGAHTTPApiResponse.Created||u==c.EGAHTTPApiResponse.BadRequest){var d=r?JSON.parse(r):{};if(null==d)return t(c.EGAHTTPApiResponse.JsonDecodeFailed,null,a,o),void A.instance.sendSdkErrorEvent(v.Http,g.EventsHttp,f.FailHttpJsonDecode,m.Undefined,r,E.getGameKey(),E.getGameSecret());c.EGAHTTPApiResponse.BadRequest,t(u,d,a,o)}else t(u,null,a,o)},A.sendRequest=function(e,n,t,i,r,s){var a=new XMLHttpRequest,o=E.getGameSecret(),u=l.getHmac(o,n),d=[];for(var c in d.push(u),t)d.push(t[c]);if(a.onreadystatechange=function(){4===a.readyState&&r(a,e,s,d)},a.open("POST",e,!0),a.setRequestHeader("Content-Type","application/json"),a.setRequestHeader("Authorization",u),i)throw new Error("gzip not supported");try{a.send(n)}catch(e){console.error(e.stack)}},A.initRequestCallback=function(e,n,t,i){var r,s;void 0===i&&(i=null),i[0],i[1],r=e.responseText,s=e.status;var a=r?JSON.parse(r):{},o=A.instance.processRequestResponse(s,e.statusText,r,"Init");if(o==c.EGAHTTPApiResponse.Ok||o==c.EGAHTTPApiResponse.Created||o==c.EGAHTTPApiResponse.BadRequest){if(null==a)return t(c.EGAHTTPApiResponse.JsonDecodeFailed,null,"",0),void A.instance.sendSdkErrorEvent(v.Http,g.InitHttp,f.FailHttpJsonDecode,m.Undefined,r,E.getGameKey(),E.getGameSecret());if(o!==c.EGAHTTPApiResponse.BadRequest){var u=h.validateAndCleanInitRequestResponse(a,o===c.EGAHTTPApiResponse.Created);u?t(o,u,"",0):t(c.EGAHTTPApiResponse.BadResponse,null,"",0)}else t(o,null,"",0)}else t(o,null,"",0)},A.prototype.createPayloadData=function(e,n){if(n)throw new Error("gzip not supported");return e},A.prototype.processRequestResponse=function(e,n,t,i){return t?200===e?c.EGAHTTPApiResponse.Ok:201===e?c.EGAHTTPApiResponse.Created:0===e||401===e?c.EGAHTTPApiResponse.Unauthorized:400===e?c.EGAHTTPApiResponse.BadRequest:500===e?c.EGAHTTPApiResponse.InternalServerError:c.EGAHTTPApiResponse.UnknownResponseCode:c.EGAHTTPApiResponse.NoResponse},A.sdkErrorCategoryString=function(e){switch(e){case v.EventValidation:return"event_validation";case v.Database:return"db";case v.Init:return"init";case v.Http:return"http";case v.Json:return"json"}return""},A.sdkErrorAreaString=function(e){switch(e){case g.BusinessEvent:return"business";case g.ResourceEvent:return"resource";case g.ProgressionEvent:return"progression";case g.DesignEvent:return"design";case g.ErrorEvent:return"error";case g.InitHttp:return"init_http";case g.EventsHttp:return"events_http";case g.ProcessEvents:return"process_events";case g.AddEventsToStore:return"add_events_to_store"}return""},A.sdkErrorActionString=function(e){switch(e){case f.InvalidCurrency:return"invalid_currency";case f.InvalidShortString:return"invalid_short_string";case f.InvalidEventPartLength:return"invalid_event_part_length";case f.InvalidEventPartCharacters:return"invalid_event_part_characters";case f.InvalidStore:return"invalid_store";case f.InvalidFlowType:return"invalid_flow_type";case f.StringEmptyOrNull:return"string_empty_or_null";case f.NotFoundInAvailableCurrencies:return"not_found_in_available_currencies";case f.InvalidAmount:return"invalid_amount";case f.NotFoundInAvailableItemTypes:return"not_found_in_available_item_types";case f.WrongProgressionOrder:return"wrong_progression_order";case f.InvalidEventIdLength:return"invalid_event_id_length";case f.InvalidEventIdCharacters:return"invalid_event_id_characters";case f.InvalidProgressionStatus:return"invalid_progression_status";case f.InvalidSeverity:return"invalid_severity";case f.InvalidLongString:return"invalid_long_string";case f.DatabaseTooLarge:return"db_too_large";case f.DatabaseOpenOrCreate:return"db_open_or_create";case f.JsonError:return"json_error";case f.FailHttpJsonDecode:return"fail_http_json_decode";case f.FailHttpJsonEncode:return"fail_http_json_encode"}return""},A.sdkErrorParameterString=function(e){switch(e){case m.Currency:return"currency";case m.CartType:return"cart_type";case m.ItemType:return"item_type";case m.ItemId:return"item_id";case m.Store:return"store";case m.FlowType:return"flow_type";case m.Amount:return"amount";case m.Progression01:return"progression01";case m.Progression02:return"progression02";case m.Progression03:return"progression03";case m.EventId:return"event_id";case m.ProgressionStatus:return"progression_status";case m.Severity:return"severity";case m.Message:return"message"}return""},A.instance=new A,A.MAX_ERROR_MESSAGE_LENGTH=256,n=A,c.GAHTTPApi=n}(gameanalytics=gameanalytics||{}),function(v){var g,f,m,p,E,S,h,d,y,A,e;function C(){}g=v.events||(v.events={}),f=v.store.GAStore,m=v.store.EGAStore,p=v.store.EGAStoreArgsOperator,E=v.state.GAState,S=v.logging.GALogger,h=v.utilities.GAUtilities,d=v.http.EGAHTTPApiResponse,y=v.http.GAHTTPApi,A=v.validators.GAValidator,C.addSessionStartEvent=function(){if(E.isEventSubmissionEnabled()){var e={};e.category=C.CategorySessionStart,E.incrementSessionNum(),f.setItem(E.getGameKey(),E.SessionNumKey,E.getSessionNum().toString()),C.addDimensionsToEvent(e),C.addEventToStore(e),S.i("Add SESSION START event"),C.processEvents(C.CategorySessionStart,!1)}},C.addSessionEndEvent=function(){if(E.isEventSubmissionEnabled()){var e=E.getSessionStart(),n=E.getClientTsAdjusted()-e;n<0&&(S.w("Session length was calculated to be less then 0. Should not be possible. Resetting to 0."),n=0);var t={};t.category=C.CategorySessionEnd,t.length=n,C.addDimensionsToEvent(t),C.addEventToStore(t),S.i("Add SESSION END event."),C.processEvents("",!1)}},C.addBusinessEvent=function(e,n,t,i,r,s){if(void 0===r&&(r=null),E.isEventSubmissionEnabled()){var a=A.validateBusinessEvent(e,n,r,t,i);if(null==a){var o={};E.incrementTransactionNum(),f.setItem(E.getGameKey(),E.TransactionNumKey,E.getTransactionNum().toString()),o.event_id=t+":"+i,o.category=C.CategoryBusiness,o.currency=e,o.amount=n,o[E.TransactionNumKey]=E.getTransactionNum(),r&&(o.cart_type=r),C.addDimensionsToEvent(o),C.addFieldsToEvent(o,E.validateAndCleanCustomFields(s)),S.i("Add BUSINESS event: {currency:"+e+", amount:"+n+", itemType:"+t+", itemId:"+i+", cartType:"+r+"}"),C.addEventToStore(o)}else y.instance.sendSdkErrorEvent(a.category,a.area,a.action,a.parameter,a.reason,E.getGameKey(),E.getGameSecret())}},C.addResourceEvent=function(e,n,t,i,r,s){if(E.isEventSubmissionEnabled()){var a=A.validateResourceEvent(e,n,t,i,r,E.getAvailableResourceCurrencies(),E.getAvailableResourceItemTypes());if(null==a){e===v.EGAResourceFlowType.Sink&&(t*=-1);var o={},u=C.resourceFlowTypeToString(e);o.event_id=u+":"+n+":"+i+":"+r,o.category=C.CategoryResource,o.amount=t,C.addDimensionsToEvent(o),C.addFieldsToEvent(o,E.validateAndCleanCustomFields(s)),S.i("Add RESOURCE event: {currency:"+n+", amount:"+t+", itemType:"+i+", itemId:"+r+"}"),C.addEventToStore(o)}else y.instance.sendSdkErrorEvent(a.category,a.area,a.action,a.parameter,a.reason,E.getGameKey(),E.getGameSecret())}},C.addProgressionEvent=function(e,n,t,i,r,s,a){if(E.isEventSubmissionEnabled()){var o=C.progressionStatusToString(e),u=A.validateProgressionEvent(e,n,t,i);if(null==u){var d,c={};d=t?i?n+":"+t+":"+i:n+":"+t:n,c.category=C.CategoryProgression,c.event_id=o+":"+d;var l=0;s&&e!=v.EGAProgressionStatus.Start&&(c.score=r),e===v.EGAProgressionStatus.Fail&&E.incrementProgressionTries(d),e===v.EGAProgressionStatus.Complete&&(E.incrementProgressionTries(d),l=E.getProgressionTries(d),c.attempt_num=l,E.clearProgressionTries(d)),C.addDimensionsToEvent(c),C.addFieldsToEvent(c,E.validateAndCleanCustomFields(a)),S.i("Add PROGRESSION event: {status:"+o+", progression01:"+n+", progression02:"+t+", progression03:"+i+", score:"+r+", attempt:"+l+"}"),C.addEventToStore(c)}else y.instance.sendSdkErrorEvent(u.category,u.area,u.action,u.parameter,u.reason,E.getGameKey(),E.getGameSecret())}},C.addDesignEvent=function(e,n,t,i){if(E.isEventSubmissionEnabled()){var r=A.validateDesignEvent(e);if(null==r){var s={};s.category=C.CategoryDesign,s.event_id=e,t&&(s.value=n),C.addDimensionsToEvent(s),C.addFieldsToEvent(s,E.validateAndCleanCustomFields(i)),S.i("Add DESIGN event: {eventId:"+e+", value:"+n+"}"),C.addEventToStore(s)}else y.instance.sendSdkErrorEvent(r.category,r.area,r.action,r.parameter,r.reason,E.getGameKey(),E.getGameSecret())}},C.addErrorEvent=function(e,n,t){if(E.isEventSubmissionEnabled()){var i=C.errorSeverityToString(e),r=A.validateErrorEvent(e,n);if(null==r){var s={};s.category=C.CategoryError,s.severity=i,s.message=n,C.addDimensionsToEvent(s),C.addFieldsToEvent(s,E.validateAndCleanCustomFields(t)),S.i("Add ERROR event: {severity:"+i+", message:"+n+"}"),C.addEventToStore(s)}else y.instance.sendSdkErrorEvent(r.category,r.area,r.action,r.parameter,r.reason,E.getGameKey(),E.getGameSecret())}},C.processEvents=function(e,n){if(E.isEventSubmissionEnabled())try{var t=h.createGuid();n&&(C.cleanupEvents(),C.fixMissingSessionEndEvents());var i=[];i.push(["status",p.Equal,"new"]);var r=[];r.push(["status",p.Equal,"new"]),e&&(i.push(["category",p.Equal,e]),r.push(["category",p.Equal,e]));var s=[];s.push(["status",t]);var a=f.select(m.Events,i);if(!a||0==a.length)return S.i("Event queue: No events to send"),void C.updateSessionStore();if(a.length>C.MaxEventCount){if(!(a=f.select(m.Events,i,!0,C.MaxEventCount)))return;var o=a[a.length-1].client_ts;if(i.push(["client_ts",p.LessOrEqual,o]),!(a=f.select(m.Events,i)))return;r.push(["client_ts",p.LessOrEqual,o])}if(S.i("Event queue: Sending "+a.length+" events."),!f.update(m.Events,s,r))return;for(var u=[],d=0;d { - let arr = [] - for (let i = 0; i < rows; i++) arr[i] = [] - return arr -} - -const dataCreator = (rowCount, columnCount) => ({ - roomId: undefined, - userId: undefined, - score: 0, - opponentScore: 0, - row: rowCount, - column: columnCount, - name: 'نامشخص', - opponentName: 'نامشخص', - letter: undefined, - role: undefined, - color: 'red', - opponentColor: 'blue', - end: false, - permission: false, - waiting: false, - gift: false, - language: 'persian', - table: { - lines: [], - squares: [], - }, -}) - -var data = dataCreator(6, 6) - -export const get = (key) => data[key] - -export const set = (key, value) => { - data[key] = value - showTurn() -} -export const reset = () => { - render() - showTurn() -} -const initializeArray = (array, type, length) => { - if (type == 'lines') - for (let i = 1; i <= length; i++) get('table').lines[i] = 0 - else if (type == 'squares') - for (let i = 0; i < length; i++) - for (let j = 0; j < length; j++) array[i][j] = 0 -} - -get('table').squares = create2DArray(get('row')) -initializeArray(get('table').squares, 'squares', get('table').squares.length) -initializeArray(get('table').lines, 'lines', 2 * get('row') * (get('row') - 1)) - -export const addCondition = (i, j) => { - get('table').squares[i][j] = get('table').squares[i][j] + 1 -} - -export const messages = { - english: { - waiting: 'waiting for opponent...', - languageButton: 'english', - resignButton: 'resign', - header: 'Dots and Boxes', - winner: 'winner', - loser: 'loser', - subscriber: 'subscriber', - }, - persian: { - waiting: 'در انتظار حریف...', - languageButton: 'فارسی', - resignButton: 'تسلیم', - header: 'نقطه‌بازی', - winner: 'برنده', - loser: 'بازنده', - subscriber: 'تماشاچی', - }, -} diff --git a/frontend/game/src/components/rectangle/rectangle.js b/frontend/game/src/components/rectangle/rectangle.js index b8079a0..2dd6962 100644 --- a/frontend/game/src/components/rectangle/rectangle.js +++ b/frontend/game/src/components/rectangle/rectangle.js @@ -4,12 +4,16 @@ import useStyle from './rectangle.style' // localiztion import t from './rectangle.local' import { + addNewLine, elementColorView, getPlayerHasPermission, + increaseOpponentScore, + increasePlayerScore, playerColorView, } from '../../scenes/_slice/game.slice' import { useSelector } from 'react-redux' import { requestGift, sendBouns } from '../../services/backend/backend.service' +import { dispatch } from '../../setup/store/store' export default function Rectangle({ i, j, lastMove }) { const classes = useStyle() @@ -29,14 +33,16 @@ export default function Rectangle({ i, j, lastMove }) { if (i + 1 === lastI && j === lastJ) lastLineColor = downLineColor || '' if (i === lastI && j - 1 === lastJ) lastLineColor = leftLineColor || '' if (i === lastI && j + 1 === lastJ) lastLineColor = rightLineColor || '' - // if (i === 2 && j === 10) console.log(lastLineColor) const backgroundColor = background - ? `dark${background}` + ? background : !!topLineColor && !!rightLineColor && !!leftLineColor && !!downLineColor - ? `dark${lastLineColor}` + ? lastLineColor : '' - + if (!background && backgroundColor) { + console.log({ backgroundColor }) + dispatch(addNewLine({ i, j, color: backgroundColor })) + } if ( ((i - 1 === lastI && j === lastJ) || (i + 1 === lastI && j === lastJ) || @@ -47,10 +53,13 @@ export default function Rectangle({ i, j, lastMove }) { !!rightLineColor && !!leftLineColor && !!downLineColor && - playerColor === lastColor + !playerHasPermission ) { - // console.log({ playerColor, lastColor, lastLineColor }) - sendBouns(i, j, playerColor) + console.log({ playerColor, lastColor, background }) + if (playerColor === lastColor) { + dispatch(increasePlayerScore()) + sendBouns(i, j, playerColor) + } else dispatch(increaseOpponentScore()) } return (
diff --git a/frontend/game/src/scenes/_slice/game.slice.js b/frontend/game/src/scenes/_slice/game.slice.js index ed13e57..2acf7f4 100644 --- a/frontend/game/src/scenes/_slice/game.slice.js +++ b/frontend/game/src/scenes/_slice/game.slice.js @@ -91,6 +91,12 @@ const gameSlice = createSlice({ const { history } = action.payload state.room.history = history }, + increasePlayerScore: (state, aciton) => { + state.player.score += 1 + }, + increaseOpponentScore: (state, aciton) => { + state.opponent.score += 1 + }, }, }) @@ -109,6 +115,8 @@ export const { setPlayerLastMove, setOpponentLastMove, setRoomLastMove, + increasePlayerScore, + increaseOpponentScore, } = actions export default reducer diff --git a/frontend/gameRender.js b/frontend/gameRender.js deleted file mode 100644 index 88987ba..0000000 --- a/frontend/gameRender.js +++ /dev/null @@ -1,365 +0,0 @@ -import { get, set, messages } from './data.js' -import { - addLineToSquare, - checkCondition, - findSpace, - checkEnd, - markLine, - checkah, - getNumberOfLine, -} from './logic.js' -import { send, requestGift, sendMessage } from './router.js' -import { getUserFirstName } from './index.js' - -const oddScale = 1 -const evenScale = 4 -const paper = document.getElementById('paper') -const header = document.getElementById('header') -const xlines = document.getElementsByClassName('xline') -const ylines = document.getElementsByClassName('yline') -const input = document.getElementById('input') -const sendButton = document.getElementsByClassName('send-button')[0] -const sendPanel = document.getElementById('send-panel') -const buttonContainer = document.getElementById('button-container') -const yourMessage = document.getElementsByClassName('your-message')[0] -const blue = document.getElementsByClassName('blue')[0] -const red = document.getElementsByClassName('red')[0] -const infoContainer = document.getElementById('info-container') -const fullInformation = document.getElementsByClassName('full-information')[0] - -const audio = new Audio('./assets/line2.mp3') -const sendAudio = new Audio('./assets/i-demand-attention-244.mp3') - -let timeout -const sendMessageInitializer = () => { - sendButton.addEventListener('click', () => { - if (input.value) { - clearTimeout(timeout) - sendAudio.play() - yourMessage.style.display = 'block' - yourMessage.innerHTML = input.value - sendMessage(input.value) - input.value = '' - setTimeout(() => (yourMessage.style.display = 'none'), 20000) - } - }) - input.addEventListener('keypress', (e) => { - if (e.key === 'Enter') { - if (input.value) { - clearTimeout(timeout) - sendAudio.play() - yourMessage.style.display = 'block' - yourMessage.innerHTML = input.value - sendMessage(input.value) - input.value = '' - timeout = setTimeout(() => (yourMessage.style.display = 'none'), 20000) - } - } - }) -} - -export const render = () => { - createElements() - stylePaperBy('row') - stylePaperBy('column') - lineInitializer(xlines, 'click') - lineInitializer(ylines, 'click') - lineInitializer(xlines, 'touch') - lineInitializer(ylines, 'touch') - changeLanguage('click') - changeLanguage('touch') - sendMessageInitializer() - show('touch', header, infoContainer) - show('click', header, infoContainer) - show('touch', buttonContainer, sendPanel) - show('click', buttonContainer, sendPanel) - // show('click', red, fullInformation, 'red') - // show('click', blue, fullInformation, 'blue') -} - -const show = (event, key, value, className) => { - key.addEventListener(event, () => { - if (value.style.display === 'flex') value.style.display = 'none' - else value.style.display = 'flex' - if (className) { - value.classList.remove(`${className === 'red' ? 'blue' : 'red'}-info`) - value.classList.add(`${className}-info`) - } - }) -} - -const lineInitializer = (array, event) => { - for (let i = 0; i < array.length; i++) - array[i].addEventListener(event, () => { - hitLine(array[i], get('color')) - if (get('gift')) requestGift() - set('gift', false) - }) -} - -export const canHit = (line, color) => { - return ( - (get('permission') || color === get('opponentColor')) && - get('role') !== 'subscriber' && - !get('waiting') && - !get('end') && - get('table').lines[getNumberOfLine(line)] !== 1 - ) -} - -export const helpLine = (line, color) => { - colorLine(line, color) - addLineToSquare(line) - markLine(line) - checkCondition(color) - checkEnd() -} - -export const hitLine = (line, color) => { - if (canHit(line, color)) { - helpLine(line, checkah()) - audio.play() - send(line) - set('permission', false) - } -} - -export const colorLine = (line, color) => { - line.style.backgroundColor = color -} - -const createElements = () => { - for (let i = 1; i <= 2 * get('row') - 1; i++) - for (let j = 1; j <= 2 * get('column') - 1; j++) { - const div = document.createElement('div') - div.setAttribute('class', 'grid-item') - div.setAttribute('i', i) - div.setAttribute('j', j) - paper.appendChild(div) - alignStyle(div, i, j) - } -} -const stylePaperBy = (orientation) => { - let template = '' - for (let k = 0; k < 2 * get('row') - 1; k++) - if (k % 2 === 0) template += oddScale + 'fr ' - else template += evenScale + 'fr ' - if (orientation === 'row') paper.style.gridTemplateRows = template - else if (orientation === 'column') paper.style.gridTemplateColumns = template -} - -const dotsData = { - green: { - count: 0, - nextColor: 'orange', - message: 'احسنت! یه مورد ویژگی جدید پیدا کردی', - }, - orange: { - count: 36, - nextColor: 'rebeccapurple', - message: 'رنگ تغییر یافت به بنفش', - }, - rebeccapurple: { - count: 0, - nextColor: 'green', - message: 'رنگ تغییر یافت به سبز', - }, -} - -const clickDot = (div) => { - const currentColor = div.style.backgroundColor - console.log(currentColor) - const { nextColor, message } = dotsData[currentColor] - console.log(dotsData[currentColor]) - div.style.backgroundColor = nextColor - - dotsData[currentColor].count -= 1 - dotsData[nextColor].count += 1 - if (dotsData[nextColor].count === 36) { - showMessage(message) - buttonContainer.style.backgroundColor = nextColor - header.style.backgroundColor = nextColor - nextColor !== 'orange' - ? (header.style.color = 'white') - : (header.style.color = 'black') - dotsData[nextColor].count = 0 - } else - get('waiting') - ? (header.innerHTML = 'در انتظار حریف...') - : (header.innerHTML = 'نقطه‌بازی') -} - -const initializeDot = (div) => { - div.style.backgroundColor = 'orange' - div.addEventListener('click', () => clickDot(div)) -} - -const alignStyle = (div, i, j) => { - if ((i * j) % 2 === 1) setDivStyle(div, `${j}`, `${i}`, 'dot') - else if (i % 2 === 1 && j % 2 !== 1) - setDivStyle(div, `${j - 1} / ${j + 2}`, `${i}`, 'xline') - else if (i % 2 !== 1 && j % 2 === 1) - setDivStyle(div, `${j}`, `${i - 1} / ${i + 2}`, 'yline') - else setDivStyle(div, `${j - 1} / ${j + 2}`, `${i - 1} / ${i + 2}`, 'space') -} - -const setDivStyle = (div, col, row, styleClass) => { - div.style.gridColumn = col - div.style.gridRow = row - div.setAttribute('class', styleClass) - if (styleClass === 'space') div.setAttribute('line', 0) - if (styleClass === 'dot') initializeDot(div) -} - -export const updateScoreBoard = () => { - const myElement = document.getElementsByClassName(get('color'))[0] - const oppElement = document.getElementsByClassName(get('opponentColor'))[0] - myElement.innerHTML = get('name') + ': ' + get('score') - oppElement.innerHTML = get('opponentName') + ': ' + get('opponentScore') -} - -export const updateScore = (color) => { - if (get('color') === color) set('score', get('score') + 1) - else if (get('opponentColor') === color) - set('opponentScore', get('opponentScore') + 1) - updateScoreBoard() -} - -export const showTurn = () => { - const isMyTurn = get('permission') - const myColor = get('color') - const oppColor = get('opponentColor') - const myElement = document.getElementsByClassName(get('color'))[0] - const oppElement = document.getElementsByClassName(get('opponentColor'))[0] - myElement.classList.toggle(`active-${myColor}`, isMyTurn) - oppElement.classList.toggle(`active-${oppColor}`, !isMyTurn) - myElement.innerHTML = get('name') + ': ' + get('score') - oppElement.innerHTML = get('opponentName') + ': ' + get('opponentScore') -} - -export const showEnd = (winner) => { - const myColor = get('color') - document.body.style.backgroundColor = 'dark' + winner - if (winner === myColor) { - showMessage('winner') - gameanalytics.GameAnalytics.addProgressionEvent( - gameanalytics.EGAProgressionStatus.Fail, - 'main', - 'main', - 'main', - get('score') - ) - gameanalytics.GameAnalytics.addProgressionEvent( - gameanalytics.EGAProgressionStatus.Complete, - 'main', - 'main', - 'main', - get('opponentScore') - ) - } else showMessage('loser') - set('end', true) -} - -export const colorBox = (i, j, color) => { - const space = findSpace(i, j) - space.style.backgroundColor = 'dark' + color - if (color === 'red') space.innerHTML = 'ق' - else space.innerHTML = 'آ' -} - -export const getMesaageOfLanguge = (type) => { - if (get('language') === 'english') { - switch (type) { - case 'waiting': - header.innerHTML = messages.english.waiting - break - case 'header': - header.innerHTML = messages.english.header - break - case 'winner': - header.innerHTML = messages.english.winner - break - case 'loser': - header.innerHTML = messages.english.loser - break - case 'resign': - document.getElementById('resign').innerHTML = messages.english.resign - break - case 'language': - document.getElementById('language').innerHTML = - messages.english.language - break - case 'subscriber': - header.innerHTML = messages.english.subscriber - break - } - } else if (get('language') === 'persian') { - switch (type) { - case 'waiting': - header.innerHTML = messages.persian.waiting - break - case 'header': - header.innerHTML = messages.persian.header - break - case 'winner': - header.innerHTML = messages.persian.winner - break - case 'loser': - header.innerHTML = messages.persian.loser - break - case 'resign': - document.getElementById('resign').innerHTML = messages.persian.resign - break - case 'language': - document.getElementById('language').innerHTML = - messages.persian.language - break - case 'subscriber': - header.innerHTML = messages.persian.subscriber - break - default: - header.innerHTML = type - } - } -} - -export const showMessage = (message) => { - if (message !== 'header') header.style.fontSize = '25px' - else header.style.fontSize = '40px' - getMesaageOfLanguge(message) -} - -export const initializeTurn = () => { - const myColor = get('color') - if (myColor === 'red') { - set('permission', true) - set('opponentColor', 'blue') - } else { - set('permission', false) - set('opponentColor', 'red') - } - set('name', getUserFirstName()) -} - -export const changeLanguage = (event) => { - const language = document.getElementById('language') - if (language !== null) { - language.addEventListener(event, () => { - if (get('language') === 'persian') { - header.innerHTML = messages.english.header - document.getElementById('resign').innerHTML = - messages.english.resignButton - document.getElementById('language').innerHTML = - messages.english.languageButton - set('language', 'english') - } else { - header.innerHTML = messages.persian.header - document.getElementById('resign').innerHTML = - messages.persian.resignButton - document.getElementById('language').innerHTML = - messages.persian.languageButton - set('language', 'persian') - } - }) - } -} diff --git a/frontend/gameStyle.css b/frontend/gameStyle.css deleted file mode 100644 index c8cc4a6..0000000 --- a/frontend/gameStyle.css +++ /dev/null @@ -1,295 +0,0 @@ -@font-face { - font-family: Vazir; - src: url('./Vazir-FD.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} -* { - font-family: Vazir; -} -body { - width: 100vw; - height: 100vh; - margin: 0; - background-color: gray; - display: flex; - flex-direction: column; - user-select: none; -} - -#root-container { - margin: auto; - display: flex; - flex-direction: column; - grid-template-columns: 1fr 1fr; - box-shadow: 15px 10px 20px 0 #00000073; - border-radius: 50px 50px 50px 50px; -} -#header { - direction: rtl; - display: flex; - justify-content: center; - align-items: center; - color: black; - cursor: pointer; - grid-area: header; - font-size: 40px; - height: 80px; - text-align: center; - border-radius: 50px 50px 0 0; - background-color: orange; -} -#info-container { - grid-area: info-container; - display: none; - height: 40px; - justify-content: center; - align-items: center; - background-color: wheat; -} -#github { - height: 30px; - margin-top: 10px; -} -#github:hover { - height: 35px; -} - -#paper { - grid-area: paper; - padding: 30px; - display: grid; - width: 65vmin; - height: 65vmin; - background-color: rgb(46, 46, 46); -} - -.score-board { - display: flex; - width: 100%; -} - -.score { - text-align: center; - text-shadow: thistle; - color: white; - font-size: 20px; - margin-bottom: 0; - width: 50%; -} - -.blue { - padding: auto; - - background-color: rgb(0, 0, 80); - box-shadow: 0 5px rgb(0, 0, 80); - transition: 2s; - - margin-bottom: 6px; -} -.active-blue { - background-color: rgb(0, 0, 235) !important; - box-shadow: 0 5px rgb(0, 0, 180) !important; - transition: 2s; -} - -.red { - padding: auto; - - background-color: rgb(100, 0, 0); - box-shadow: 0 5px rgb(100, 0, 0); - transition: 2s; - - margin-bottom: 6px; -} - -.active-red { - background-color: red !important; - box-shadow: 0 5px rgb(200, 0, 0) !important; - transition: 2s; -} - -.full-information { - flex-grow: 1; - width: 100%; - height: 100px; - display: none; - color: white; -} - -.red-info { - background-color: rgb(100, 0, 0); - direction: rtl; -} - -.blue-info { - background-color: rgb(0, 0, 100); - direction: ltr; -} - -.facts { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 5px; - width: 100%; -} - -.full-name { - font-size: 20px; -} - -.avatar { - width: 80px; - height: 80px; - border-radius: 100%; - padding: 10px; - transition: all 0.35s ease; -} - -.your-message { - background-color: yellowgreen; - position: absolute; - right: 10px; - top: 10px; - padding: 5px; - border-radius: 5px 5px 0 5px; - transition: all 0.35s ease-in-out; - display: none; - direction: rtl; -} -.opponent-message { - background-color: rgb(227, 255, 65); - position: absolute; - left: 10px; - top: 10px; - padding: 5px; - border-radius: 5px 5px 5px 0; - transition: all 0.35s ease-in-out; - display: none; - direction: rtl; -} - -#send-panel { - display: none; - grid-area: message; - width: 100%; - height: 40px; - background-color: wheat; -} -.send-button { - background-color: orange; - border: 2px solid wheat; - width: 50px; - cursor: pointer; - border-radius: 10px; -} - -#send:active { - background-color: rgb(255, 145, 0); -} - -.send-button > img { - transform: scaleX(-1); - height: 100%; - width: 100%; -} -#input { - direction: rtl; - background-color: wheat; - border: 2px solid wheat; - flex-grow: 4; -} - -#input:focus { - outline: none; -} - -#button-container { - grid-area: buttons; - height: 50px; - display: flex; - align-items: center; - justify-content: center; - background-color: orange; - border-radius: 0 0 50px 50px; - cursor: pointer; -} -#buttons { - display: flex; - flex-direction: row; - justify-content: center; - grid-area: area; -} - -.button { - color: black; - font-size: 20px; - cursor: pointer; - - margin: 5px; - padding: 10px; - border-radius: 30px; - border-bottom: solid orangered; - border-top: solid orangered; - - display: flex; - justify-content: center; - align-items: center; -} -.button:hover { - font-size: 25px; -} -.grid-item { - width: 100%; - height: 100%; - display: flex; -} -.xline { - position: relative; - height: 60%; - width: 90%; - transition: all 0.5s; - border-radius: 15px; - margin: auto; -} -.xline:hover { - background-color: rgb(65, 65, 65); -} -.yline { - position: relative; - height: 90%; - width: 60%; - border-radius: 15px; - margin: auto; - transition: all 0.5s; -} -.yline:hover { - background-color: rgb(65, 65, 65); -} -.dot { - z-index: 1000; - width: 100%; - height: 100%; - border-radius: 99999999px; - background-color: yellow; - margin: auto; - box-shadow: 10px purple; -} -.dot:hover { - background-color: orange; -} -.space { - display: flex; - justify-content: center; - align-items: center; - font-size: 180%; - color: white; - text-align: center; - height: 90%; - width: 90%; - border-radius: 15px; - margin: auto; - transition: all 0.5s ease-in; -} diff --git a/frontend/icon.jpg b/frontend/icon.jpg deleted file mode 100644 index 7e05c7c..0000000 Binary files a/frontend/icon.jpg and /dev/null differ diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index 237a963..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - Dots and Boxes - - - - - - - - - - -
- -
- github -
-
-
-
آبی: 0
-
قرمز: 0
-
-
- avatar -
- محمدحسین دولت‌آبادی - -
-
-
-
- فرستادن -
- -
-
- - - -
-
-
شما: چه حرکت خفنی! احسنت
-
محمدحسین: قربون شما!
- -