├── src ├── elance.scala ├── runServer.bat ├── runClient.bat ├── README.txt ├── client.bat ├── server.bat ├── Player.scala ├── TabuCard.scala ├── Team.scala ├── CLICommandActor.scala ├── Server.scala ├── SocketActor.scala ├── GameHall.scala ├── Client.scala ├── Command.scala └── Game.scala ├── README ├── src.zip ├── .gitattributes └── .gitignore /src/elance.scala: -------------------------------------------------------------------------------- 1 | e -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | A project of the game tabu for my University 2 | -------------------------------------------------------------------------------- /src/runServer.bat: -------------------------------------------------------------------------------- 1 | start cmd /k scala -cp ../release TabuServer -------------------------------------------------------------------------------- /src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drFabio/ScalaTabu/master/src.zip -------------------------------------------------------------------------------- /src/runClient.bat: -------------------------------------------------------------------------------- 1 | start cmd /k scala -cp ../release TabuClient 2 | start cmd /k scala -cp ../release TabuClient -------------------------------------------------------------------------------- /src/README.txt: -------------------------------------------------------------------------------- 1 | Como compilar: 2 | scalac -d release Game.scala Payer.scala GameHall.scala Main.scala 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/client.bat: -------------------------------------------------------------------------------- 1 | scalac -d ../release TabuCard.scala Command.scala CLICommandActor.scala SocketActor.scala Client.scala -deprecation 2 | PAUSE -------------------------------------------------------------------------------- /src/server.bat: -------------------------------------------------------------------------------- 1 | scalac -d ../release SocketActor.scala Team.scala TabuCard.scala Command.scala GameHall.scala Game.scala Player.scala Server.scala -deprecation 2 | PAUSE>nul -------------------------------------------------------------------------------- /src/Player.scala: -------------------------------------------------------------------------------- 1 | package game.basics 2 | import scala.actors.Actor 3 | //Um jogador 4 | class Player(val actor:Actor,val name:String,val connId:Int){ 5 | protected var _teamId:Option[Int]=None 6 | protected var _isReady:Boolean=false 7 | override def toString()={ 8 | name 9 | } 10 | def teamId=_teamId 11 | 12 | def teamId_= (value:Int):Unit = _teamId=Some(value) 13 | 14 | def isReady=_isReady 15 | def isReady_=(value:Boolean):Unit=_isReady=value 16 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /src/TabuCard.scala: -------------------------------------------------------------------------------- 1 | package game.basics.cards 2 | //Representa uma carta de tabu 3 | class TabuCard(val word:String,val tabuWords:List[String]) extends Serializable{ 4 | override def toString()={ 5 | " Palavara ="+word+"\n Tabus "+tabuWords.mkString("\n - ") 6 | } 7 | } 8 | //Representa um baralho de Tabu 9 | object TabuDeck{ 10 | /** 11 | * Pega um barulho de tabu 12 | */ 13 | def getCards():List[TabuCard]={ 14 | List(new TabuCard("água",List("líquido","azul","bebida","piscina")), 15 | new TabuCard("cerveja",List("líquido","beber","alcool","brejas")), 16 | new TabuCard("azul",List("cores","céu","água","mar")), 17 | new TabuCard("vento",List("ar","brisa","tornado","elemento")), 18 | new TabuCard("chocolate",List("cacau","leite","doce","bombom"))) 19 | } 20 | } -------------------------------------------------------------------------------- /src/Team.scala: -------------------------------------------------------------------------------- 1 | package game.basics 2 | import scala.collection.mutable.ListBuffer 3 | /** 4 | * Classe que representa um time de infinitos jogadores 5 | */ 6 | class Team{ 7 | 8 | protected var _points:Int=0 9 | protected var _players:ListBuffer[Player]=ListBuffer() 10 | var position:Int=0 11 | //Adiciona um jogador 12 | def +(p:Player){ 13 | this._players+=p 14 | } 15 | //Remove um jogador 16 | def -(p:Player){ 17 | 18 | val index=this._players.indexOf(p) 19 | if(this.position>index){ 20 | this.position-=1 21 | } 22 | this._players.remove(index) 23 | } 24 | //Pontua 25 | def score():Int={ 26 | this._points+=1 27 | return this._points 28 | } 29 | //Pega o proximo jogador a jogar 30 | def getNextPlayer():Player={ 31 | val pos=this.position 32 | this.position=(this.position+1)%this._players.length 33 | return this._players(pos) 34 | } 35 | //Pega a quantidade de jogadores 36 | def getNumPlayers():Int={ 37 | this._players.length 38 | } 39 | //Lista de jogaodres 40 | def getPlayers():List[Player]={ 41 | return _players.toList 42 | } 43 | //Lista os jogadores retornando uma string 44 | def list():String={ 45 | var ret="" 46 | for(p<-_players){ 47 | ret+="\n\t"+p.name 48 | } 49 | ret 50 | } 51 | } -------------------------------------------------------------------------------- /src/CLICommandActor.scala: -------------------------------------------------------------------------------- 1 | package game.io 2 | import scala.actors.Actor 3 | import scala.actors.Actor._ 4 | import java.net._ 5 | import java.io._ 6 | import scala.io._ 7 | import game.io.commands._ 8 | /** 9 | * Lida com o recebimento de comandos pela interface da command line 10 | */ 11 | abstract class CLICommandActor extends CommandActor{ 12 | /** 13 | * Intepreta uma mensagem no formato string 14 | * @type {[type]} 15 | */ 16 | def handleMessage(mess:String):AbstractCommand={ 17 | if(mess.startsWith("-")){ 18 | this.interpretCommand(CLICommandActor.parseCommand(mess)) 19 | } 20 | else{ 21 | createMessage(mess) 22 | } 23 | } 24 | 25 | def createMessage(mess:String):Message 26 | /** 27 | * Interpreta um comando vindo do parser 28 | * @type {[type]} 29 | */ 30 | def interpretCommand(cmd:List[(String,Option[String])]):AbstractCommand 31 | } 32 | 33 | object CLICommandActor{ 34 | val cliRegex=new scala.util.matching.Regex("""-(\w+)(\s+(\"([\w ]+)\"|\w+))?""","cmd","dumb","value","quotedValue") 35 | /** 36 | * Interpreta linhas de comando 37 | * @type {[type]} 38 | */ 39 | def parseCommand(cmd:String):List[(String,Option[String])]={ 40 | var cmdList:Iterator[(String,Option[String])]=for(m<-cliRegex findAllMatchIn(cmd)) yield { 41 | val value=if ((m group "quotedValue" )!=null){m group "quotedValue"} else{ m group "value"} 42 | (m group "cmd",if(value==null){None} else {Some(value)}) 43 | } 44 | if(cmdList.isEmpty){ 45 | throw new IllegalArgumentException("ERRO:Por favor envie comandos no formaro -Comando Argumento -COmando2 Argumento .. -ComandoN argumento") 46 | 47 | } 48 | cmdList.toList 49 | } 50 | } -------------------------------------------------------------------------------- /src/Server.scala: -------------------------------------------------------------------------------- 1 | import java.net._ 2 | import java.io._ 3 | import scala.io._ 4 | import game.io._ 5 | import scala.actors.Actor 6 | import scala.actors.Actor._ 7 | import game.basics._ 8 | /** 9 | * Ator que cuida da obtenção de comandos vindo do socket 10 | */ 11 | class receiverActor(gh:GameHall,protected val sock:Socket,val connId:Int) extends {} with SocketActor{ 12 | protected var _name:String=null 13 | _currentRole=gh 14 | /** 15 | *Envia a mensagem de boas vindas 16 | */ 17 | def sendHello(name:String){ 18 | 19 | this.sendMessage(new commands.Message("Bem vindo "+name+"! voce esta conectado , digite -h para ajuda")) 20 | } 21 | override def handleInput(input:commands.AbstractCommand)={ 22 | input match { 23 | case c:commands.setup.IAm=>{ 24 | sendHello(c.name) 25 | } 26 | case _=>{ 27 | super.handleInput(input) 28 | } 29 | } 30 | } 31 | this.sendMessage(new commands.setup.WhoAreYou(connId)) 32 | } 33 | /** 34 | * Servidor de tabu criando um receiverActor para cada jogador 35 | */ 36 | object TabuServer{ 37 | def main(args:Array[String])={ 38 | /** 39 | * @todo pegar argumento para numero de pessoas 40 | */ 41 | val gh:GameHall=new GameHall 42 | gh.start 43 | try{ 44 | val port=1337 45 | println("Iniciando servidor na porta "+port) 46 | val server = new ServerSocket(port) 47 | var connId=0 48 | while (true) { 49 | val s = server.accept() 50 | println("Recebido conexão") 51 | val a =new receiverActor(gh,s,connId) 52 | a.start() 53 | connId+=1 54 | } 55 | } 56 | catch{ 57 | case e:Throwable=>{ 58 | e.printStackTrace() 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/SocketActor.scala: -------------------------------------------------------------------------------- 1 | package game.io 2 | import scala.actors.Actor 3 | import scala.actors.Actor._ 4 | import java.net._ 5 | import java.io._ 6 | import scala.io._ 7 | import game.io.commands._ 8 | 9 | 10 | 11 | /** 12 | * Lida com o recebimento e envio de mensagens de texto, parseando comandos e mensagens 13 | */ 14 | trait SocketActor extends Actor{ 15 | 16 | protected def sock:Socket 17 | /** 18 | * Papel que estamos desenpenhando atualmente 19 | * @type {[type]} 20 | */ 21 | protected var _currentRole:CommandActor=_ 22 | protected lazy val oin:ObjectInputStream=new ObjectInputStream(this.sock.getInputStream()) 23 | protected lazy val oout:ObjectOutputStream = new ObjectOutputStream (this.sock.getOutputStream()) 24 | /** 25 | * Comunicação entre o _currentRole e o socket 26 | */ 27 | protected lazy val internalHandler=actor{ 28 | self.loop{ 29 | self.react{ 30 | case rp:Reply=>{ 31 | sendMessage(rp.cmd) 32 | } 33 | case ic:InternalCommand=>{ 34 | handleCommand(ic) 35 | } 36 | case ac:AbstractCommand=>{ 37 | _currentRole ! ac 38 | } 39 | 40 | case ca:CommandActor=>{ 41 | changeRole(ca) 42 | } 43 | 44 | } 45 | } 46 | } 47 | internalHandler.start() 48 | 49 | 50 | /** 51 | * Le inputs vindo de um socket e lida com eles 52 | */ 53 | def act(){ 54 | try{ 55 | 56 | var ok=true 57 | while(ok){ 58 | var input=oin.readObject 59 | if(input==null){ //fim da stream ou erro provavelmente 60 | ok=false 61 | } 62 | else{ 63 | try{ 64 | input match{ 65 | case m:AbstractCommand=>handleInput(m) 66 | } 67 | 68 | } 69 | catch{ 70 | case e:IllegalArgumentException=>{ 71 | sendMessage(new ErrorMessage(e)) 72 | } 73 | 74 | } 75 | } 76 | } 77 | } 78 | catch{ 79 | 80 | case e:Throwable=>{ 81 | println("Exceção cliente finalizado") 82 | sock.close() 83 | } 84 | } 85 | 86 | } 87 | //Muda o papel atual 88 | def changeRole(ca:CommandActor){ 89 | _currentRole=ca 90 | } 91 | //Envia uma mensagem para o outro lado do socket 92 | def sendMessage(mess:AbstractCommand){ 93 | oout.writeObject(mess) 94 | } 95 | /** 96 | * Lida com o input recebifo via socket 97 | */ 98 | def handleInput(input:AbstractCommand)={ 99 | internalHandler ! input 100 | } 101 | /** 102 | * Lida com um comando vindo do papel atual 103 | */ 104 | def handleCommand(input:AbstractCommand)={ 105 | 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/GameHall.scala: -------------------------------------------------------------------------------- 1 | package game.basics 2 | import game.io.CommandActor 3 | import scala.actors.Actor 4 | import scala.actors.Actor._ 5 | import game.io.commands._ 6 | 7 | /** 8 | * Salaão de jogos 9 | */ 10 | class GameHall(val size:Int) extends CommandActor{ 11 | def help(){ 12 | sender ! new Reply(new Message("Digite -l para listar \n -j [Numero do jogo] para entrar num jogo \n -c [Nome do jogo] (-n [Numero de times] (-p [Pontos para vencer]))")) 13 | } 14 | def executeCommand(cmd:AbstractCommand){ 15 | cmd match { 16 | case c:gameHall.List=>{ 17 | sender ! new Reply(new Message(list getOrElse("Não existem jogos, crie um novo"))) 18 | } 19 | 20 | 21 | case c:gameHall.CreateGame => { 22 | 23 | val g:Option[Game]=createGame(sender.asInstanceOf[Actor],c.gameName,c.numTeams,c.maxScore,c.creatorName,c.connId) 24 | if(g.isEmpty){ 25 | sender ! new Reply(new ErrorMessage("Não foi possível criar seu jogo, tente novamente mais tarde")) 26 | } 27 | else{ 28 | val ga=g.get 29 | ga.start 30 | sender ! ga 31 | sender ! new Reply(new gameHall.CreatedGame("Jogo criado com sucesso!")) 32 | } 33 | } 34 | case c:gameHall.JoinGame=>{ 35 | if(_gameBuffer(c.gameId)==null){ 36 | throw new IllegalArgumentException("O jogo numero "+c.gameId+" não existe mais") 37 | } 38 | 39 | _gameBuffer(c.gameId).join(new Player(sender.asInstanceOf[Actor],c.playerName,c.connId)) 40 | sender ! _gameBuffer(c.gameId) 41 | sender ! new Reply(new gameHall.JoinedGame("Entrou no jogo "+_gameBuffer(c.gameId).name+" com sucesso!")) 42 | 43 | } 44 | case _=>{ 45 | 46 | } 47 | 48 | } 49 | } 50 | /** 51 | * Jogos que serão criados 52 | * @type {[type]} 53 | */ 54 | protected val _gameBuffer:Array[Game]=new Array[Game](size) 55 | protected var _gamesOn=0 56 | 57 | println("Salao de jogos inciado com uma capacidade para "+size+" jogos") 58 | def this()=this(10) 59 | 60 | /** 61 | * Lista as Salas 62 | */ 63 | def list():Option[String]={ 64 | var ret:String="" 65 | for(g<-_gameBuffer if g !=null){ 66 | if(ret!=""){ 67 | ret+="\n" 68 | } 69 | ret+=g 70 | } 71 | return if(ret==""){ 72 | None 73 | } 74 | else{ 75 | Some(ret) 76 | } 77 | } 78 | /** 79 | * Cria um novo jogo com o numero de times e o score desejado 80 | * @type {[type]} 81 | */ 82 | def createGame(creatorActor:Actor,name:String, numTeams:Int, maxScore:Int,creatorName:String,creatorConnId:Int):Option[Game]={ 83 | if(_gamesOn==this.size){ 84 | return None 85 | } 86 | for((x,i) <- _gameBuffer.view.zipWithIndex if x==null){ 87 | 88 | _gamesOn+=1 89 | _gameBuffer(i)=new Game(new Player(creatorActor,creatorName,creatorConnId),i,name,numTeams,maxScore) 90 | return Some(_gameBuffer(i)) 91 | 92 | } 93 | return None 94 | } 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /src/Client.scala: -------------------------------------------------------------------------------- 1 | import java.net._ 2 | import java.io._ 3 | import scala.io._ 4 | import game.io._ 5 | import game.io.commands._ 6 | //import game.basics._ 7 | /** 8 | * Ator que cuida da obtenção de comandos vindo do socket 9 | */ 10 | class PlayerActor(protected val sock:Socket,val name:String) extends{ 11 | 12 | } 13 | with SocketActor{ 14 | protected var _connId:Int=_ 15 | _currentRole=new GameHallPlayerCommand(this) 16 | _currentRole.start 17 | def sendMessage(str:String){ 18 | try{ 19 | this.sendMessage(_currentRole.asInstanceOf[CLICommandActor].handleMessage(str)) 20 | } 21 | catch{ 22 | case e:IllegalArgumentException=>_currentRole ! new ErrorMessage(e) 23 | } 24 | } 25 | override def handleCommand(input:AbstractCommand)={ 26 | input match{ 27 | case wh:setup.WhoAreYou=>{ 28 | _connId=wh.connId 29 | } 30 | } 31 | } 32 | def getConnId()={ 33 | _connId 34 | } 35 | 36 | } 37 | abstract class PlayerCLICommandActor(val pa:PlayerActor) extends CLICommandActor{ 38 | def createMessage(mess:String):Message={ 39 | new Message(mess,Some(pa.name),Some(pa.getConnId)) 40 | } 41 | def help(){ 42 | 43 | } 44 | } 45 | /** 46 | * Papeis do jogador quando ele está no gameHall 47 | * @type {[type]} 48 | */ 49 | class GameHallPlayerCommand( pa:PlayerActor) extends PlayerCLICommandActor(pa){ 50 | 51 | def interpretCommand(cmd:List[(String,Option[String])]):AbstractCommand={ 52 | cmd match{ 53 | case (h,_)::_ if (h=="h")=>new Help() 54 | case (l,_)::_ if (l=="l")=>new gameHall.List() 55 | case (c,_)::_ if (c=="c")=> gameHall.CreateGame.factory(cmd,pa.name,pa.getConnId) 56 | case (j,gameId:Some[String])::_ if (j=="j")=> new gameHall.JoinGame(gameId.get.toInt,pa.name,pa.getConnId) 57 | case _=>{ 58 | throw new IllegalArgumentException("Comando inválido") 59 | } 60 | } 61 | } 62 | 63 | def executeCommand(cmd:AbstractCommand){ 64 | cmd match{ 65 | case wh:setup.WhoAreYou=>{ 66 | sender ! (new setup.WhoAreYou(wh.connId) with InternalCommand) 67 | sender ! new Reply(new setup.IAm(pa.name)) 68 | } 69 | case c:gameHall.CreatedGame=>{ 70 | display(c) 71 | val gpc=new GamePlayerCommand(pa) 72 | gpc.start 73 | sender ! gpc 74 | sender ! new Reply(new game.IAmReady(pa.getConnId)) 75 | } 76 | case c:gameHall.JoinedGame=>{ 77 | display(c) 78 | val gpc=new GamePlayerCommand(pa) 79 | gpc.start 80 | sender ! gpc 81 | sender ! new Reply(new game.IAmReady(pa.getConnId)) 82 | 83 | } 84 | case m:Message=>{ 85 | display(m) 86 | } 87 | 88 | } 89 | 90 | } 91 | } 92 | /** 93 | * Papeis do jogador quando ele está no jogo em si 94 | * @type {[type]} 95 | */ 96 | class GamePlayerCommand( pa:PlayerActor) extends PlayerCLICommandActor(pa){ 97 | var status=Status.guess 98 | def interpretCommand(cmd:List[(String,Option[String])]):AbstractCommand={ 99 | cmd match{ 100 | case (h,_)::_ if (h=="h")=>new Help() 101 | case (c,_)::_ if (c=="c")=>{ 102 | if(status!=Status.mine){ 103 | throw new IllegalArgumentException("Comando inválido no momento") 104 | } 105 | new game.Correct 106 | } 107 | case (t,_)::_ if (t=="t")=>{ 108 | if(status!=Status.atention){ 109 | throw new IllegalArgumentException("Comando inválido no momento") 110 | } 111 | new game.Tabu 112 | } 113 | case (l,_)::_ if (l=="l")=>{ 114 | new game.List 115 | } 116 | case _=>{ 117 | throw new IllegalArgumentException("Comando inválido") 118 | } 119 | 120 | } 121 | 122 | } 123 | def executeCommand(cmd:AbstractCommand){ 124 | cmd match{ 125 | case c:game.PayAtention=>{ 126 | status=Status.atention 127 | display(c+"\n"+c.card) 128 | } 129 | case c:game.YourTurn=>{ 130 | status=Status.mine 131 | display(c+"\n"+c.card) 132 | } 133 | case c:game.GuessWord=>{ 134 | status=Status.guess 135 | display(c) 136 | } 137 | case c:game.Won=>{ 138 | display(c) 139 | } 140 | case c:game.Lost=>{ 141 | display(c) 142 | } 143 | case m:Message=>{ 144 | display(m) 145 | } 146 | } 147 | } 148 | object Status extends Enumeration{ 149 | val atention,guess,mine=Value 150 | } 151 | 152 | } 153 | 154 | 155 | object TabuClient{ 156 | 157 | def main(args:Array[String]){ 158 | try{ 159 | println("Por favor digite seu nome") 160 | val name=readLine() 161 | /** 162 | * @todo pegar do argumento 163 | */ 164 | val port=1337 165 | val s = new Socket(InetAddress.getByName("localhost"), port) 166 | 167 | //Inicializa o ator que cuida dos sockets 168 | val a=new PlayerActor(s,name) 169 | a.start() 170 | //Le indefinidamente do input 171 | for (line <- io.Source.stdin.getLines if line!=null){ 172 | a.sendMessage(line) 173 | } 174 | s.close() 175 | } 176 | catch{ 177 | case e:Throwable=>{ 178 | e.printStackTrace() 179 | } 180 | 181 | } 182 | } 183 | } -------------------------------------------------------------------------------- /src/Command.scala: -------------------------------------------------------------------------------- 1 | import java.util.Calendar 2 | import game.basics.cards.TabuCard 3 | /** 4 | * Comandos enviados via socket e entre os atores 5 | */ 6 | package game.io.commands{ 7 | abstract class AbstractCommand() extends Serializable{ 8 | val now=Calendar.getInstance 9 | 10 | } 11 | /** 12 | * Uma mensagem de texto , opcionalmente com rementente 13 | * @type {[type]} 14 | */ 15 | class Message(val content:String,val senderName:Option[String],val senderConnId:Option[Int]) extends AbstractCommand{ 16 | override def toString()={ 17 | 18 | val mess=if(senderName.isEmpty){ 19 | content 20 | } 21 | else{ 22 | senderName.get+" :"+content 23 | } 24 | now.get(Calendar.HOUR_OF_DAY)+":"+now.get(Calendar.MINUTE)+" - "+mess 25 | } 26 | def this(content:String)=this(content,None,None) 27 | } 28 | 29 | class ErrorMessage(content:String) extends Message(content){ 30 | def this(e:Exception)=this(e.getMessage) 31 | } 32 | trait Command extends AbstractCommand{ 33 | 34 | } 35 | 36 | class Help() extends Command{ 37 | 38 | } 39 | /** 40 | * Devolve para a parte que enviou o comando recebido (cliente ou servidor) 41 | */ 42 | class Reply(val cmd:AbstractCommand) extends AbstractCommand{ 43 | 44 | } 45 | trait InternalCommand extends AbstractCommand{ 46 | 47 | } 48 | 49 | package setup{ 50 | class WhoAreYou(val connId:Int) extends Command{ 51 | 52 | } 53 | class IAm(val name:String) extends Command{ 54 | 55 | } 56 | } 57 | package gameHall{ 58 | class List extends Command{ 59 | 60 | } 61 | 62 | class CreateGame(val gameName:String,val numTeams:Int,val maxScore:Int,val creatorName:String,val connId:Int) extends Command{ 63 | 64 | } 65 | class JoinGame(val gameId:Int,val playerName:String,val connId:Int) extends Command{ 66 | 67 | } 68 | class CreatedGame(message:String) extends Message(message) with Command{ 69 | 70 | } 71 | class JoinedGame(message:String) extends Message(message) with Command{ 72 | 73 | } 74 | 75 | object CreateGame{ 76 | val defaultTeam:Int=2 77 | val defaultScore:Int=5 78 | 79 | def factory(cmd:_root_.scala.collection.immutable.List[(String,Option[String])],creatorName:String,connId:Int):CreateGame={ 80 | var score:Int=defaultScore 81 | var teams:Int=defaultTeam 82 | var name:String=null 83 | for(c<-cmd){ 84 | c._1 match{ 85 | case p:String if p=="c"=>name=c._2.get 86 | case p:String if p=="n"=>teams=c._2.get.toInt 87 | case p:String if p=="p"=>score=c._2.get.toInt 88 | case _=>{} 89 | } 90 | } 91 | 92 | if(score<=0){ 93 | score=CreateGame.defaultScore 94 | } 95 | if(teams<=2){ 96 | teams=CreateGame.defaultTeam 97 | } 98 | return new CreateGame(name,teams,score,creatorName,connId) 99 | } 100 | } 101 | 102 | } 103 | package game{ 104 | /** 105 | * Jogador está pronto 106 | * @type {[type]} 107 | */ 108 | class IAmReady(val connId:Int) extends Command{ 109 | 110 | } 111 | /** 112 | * Alguem do seu time acertou!! 113 | */ 114 | class Correct extends Command{ 115 | 116 | } 117 | class List extends Command{ 118 | 119 | } 120 | /** 121 | * Pessoa do time falou a palavra tabu 122 | */ 123 | class Tabu extends Command{ 124 | 125 | } 126 | /** 127 | * Vez de voce perceber se o cara falou a palavra tabu ou não 128 | */ 129 | class GuessWord(msg:String) extends Message (msg) with Command{ 130 | 131 | } 132 | /** 133 | * Vez do jogador 134 | * @type {[type]} 135 | */ 136 | class YourTurn(val card:TabuCard,msg:String) extends Message (msg) with Command{ 137 | 138 | } 139 | /** 140 | * Time oposto jogando pessoas devem reparar na carta 141 | * 142 | * @type {[type]} 143 | */ 144 | class PayAtention(val card:TabuCard,msg:String) extends Message (msg) with Command{ 145 | 146 | } 147 | 148 | class Won(msg:String) extends Message (msg) with Command{ 149 | 150 | } 151 | class Lost(msg:String) extends Message (msg) with Command{ 152 | 153 | } 154 | } 155 | } 156 | 157 | 158 | package game.io { 159 | import scala.actors.Actor 160 | import scala.actors.Actor._ 161 | import java.net._ 162 | import java.io._ 163 | import scala.io._ 164 | import game.io.commands._ 165 | 166 | /** 167 | * Classe que lida com recebimento de commandos 168 | */ 169 | abstract class CommandActor extends Actor{ 170 | /** 171 | * Executa um comando recebido 172 | * @type {[type]} 173 | */ 174 | def executeCommand(cmd:AbstractCommand) 175 | def help() 176 | def act{ 177 | loop{ 178 | react{ 179 | case h:Help=>help() 180 | case cmd:AbstractCommand =>{ 181 | try{ 182 | executeCommand(cmd) 183 | } 184 | catch{ 185 | case e:IllegalArgumentException=>{ 186 | e.printStackTrace 187 | sender ! new Reply(new ErrorMessage(e)) 188 | } 189 | } 190 | 191 | } 192 | } 193 | } 194 | } 195 | /**run 196 | * Mostra algum resultado para o usuario 197 | */ 198 | def display(mess:Message){ 199 | println(mess) 200 | } 201 | def display(str:String){ 202 | println(str) 203 | } 204 | 205 | } 206 | 207 | } -------------------------------------------------------------------------------- /src/Game.scala: -------------------------------------------------------------------------------- 1 | package game.basics 2 | import game.io.commands._ 3 | import cards.TabuCard 4 | import cards.TabuDeck 5 | /** 6 | * Uma instancai de jogos 7 | * @type {[type]} 8 | */ 9 | class Game(val creator:Player,val index:Int,val name:String,val numTeams:Int,val maxScore:Int) extends _root_.game.io.CommandActor{ 10 | protected val _teamList:Array[Team]=Array.fill(numTeams){new Team()} 11 | protected var _joinCounter=0 12 | protected var _roundCounter=0 13 | protected var _currentTeam:Int=0 14 | protected var _status=Status.WaitingPlayers 15 | protected var _cards:List[TabuCard]=Nil 16 | protected var _currentPlayer:Option[Player]=None 17 | protected var _currentCard:Option[TabuCard]=None 18 | protected var _connectionPlayerMap:Map[Int,Player]=Map() 19 | 20 | def help(){ 21 | sender ! new Reply(new Message("Digite -l para listar times e jogadores \n -t na vez de outro time para declarar que foi uma palavra tabu \n -c Na sua vez de dizer as palavras para falar que o time acertou")) 22 | } 23 | def executeCommand(cmd:AbstractCommand){ 24 | cmd match{ 25 | case c:game.IAmReady=>{ 26 | _connectionPlayerMap(c.connId).isReady=true 27 | if( _status==Status.Started){ 28 | _sendPlayerMessage(_connectionPlayerMap(c.connId)) 29 | } 30 | else if(_status==Status.WaitingPlayers && _canGameStart()){ 31 | _startGame() 32 | } 33 | 34 | } 35 | case c:game.List=>{ 36 | var msg="" 37 | for((x,i) <- _teamList.view.zipWithIndex ){ 38 | msg+="Time "+i+" "+x.list+"\n" 39 | 40 | } 41 | sender ! new Reply(new Message(msg)) 42 | } 43 | case c:game.Correct=>{ 44 | display(new Message("Palavra encontrada!")) 45 | foundWord() 46 | } 47 | case c:game.Tabu=>{ 48 | display(new Message("TABU! Jogador disse palavra proibida")) 49 | tabu() 50 | 51 | } 52 | case m:Message=>{ 53 | display(m) 54 | } 55 | } 56 | } 57 | 58 | this.join(this.creator) 59 | /** 60 | * Jogador entra 61 | */ 62 | def join(p:Player){ 63 | _connectionPlayerMap+=(p.connId->p) 64 | p.teamId=this._joinCounter 65 | this._teamList(this._joinCounter)+p 66 | this._joinCounter=(this._joinCounter+1)%this._teamList.length 67 | 68 | 69 | } 70 | /** 71 | * Checa se o jogo pode iniciar 72 | * Se todos times tem mais do que o minímo de jogadores 73 | */ 74 | protected def _canGameStart():Boolean={ 75 | for(t<-this._teamList){ 76 | if(t.getNumPlayers() < (Game.minPlayers)){ 77 | return false 78 | } 79 | var readyCount=0 80 | for(p<-t.getPlayers if p.isReady){ 81 | readyCount+=1 82 | } 83 | if(readyCount<(Game.minPlayers)){ 84 | return false 85 | } 86 | } 87 | return true 88 | } 89 | /** 90 | * Inicia o jogo 91 | */ 92 | protected def _startGame(){ 93 | _status=Status.Started 94 | _cards=TabuDeck.getCards 95 | this.display(new Message("Jogo iniciado!")) 96 | this._nextRound() 97 | } 98 | /** 99 | * Pega a proxima carta do baralho, se o baralho acabou o reembaralha 100 | */ 101 | protected def _getNextCard():TabuCard={ 102 | if(_cards==Nil){ 103 | _cards=TabuDeck.getCards 104 | } 105 | val ret=_cards.head 106 | _cards=_cards.tail 107 | ret 108 | } 109 | /** 110 | * Envia a mensagem adequada de acordo com o jogador corrente para o jogador X 111 | * @type {[type]} 112 | */ 113 | protected def _sendPlayerMessage(p:Player,currentPlayer:Player){ 114 | if(p.teamId.get==currentPlayer.teamId.get){ 115 | if(p.connId==currentPlayer.connId){ 116 | p.actor ! new Reply(new game.YourTurn(_currentCard.get,"É a sua vez ,faça adivinhar a palavra sem dizer ela, as palavras tabu ou derivados")) 117 | } 118 | else{ 119 | p.actor ! new Reply(new game.GuessWord("Advinhe a palavra de acordo com as dicas dadas")) 120 | } 121 | } 122 | else{ 123 | p.actor ! new Reply(new game.PayAtention(_currentCard.get,"É a vez do time adversário, fique atento para eles não dizerem as palavras tabu")) 124 | } 125 | } 126 | protected def _sendPlayerMessage(p:Player){ 127 | val cp:Player=_currentPlayer.get 128 | _sendPlayerMessage(p,cp) 129 | 130 | } 131 | /** 132 | * Proxima jogada 133 | */ 134 | protected def _nextPlay(){ 135 | _currentCard=Some(_getNextCard) 136 | 137 | val cp:Player=_currentPlayer.get 138 | //Envia o lookup MENOS para o time do jogador atual 139 | for(t<- _teamList){ 140 | for(p<-t.getPlayers if p.isReady){ 141 | _sendPlayerMessage(p,cp) 142 | } 143 | } 144 | } 145 | /** 146 | * Jogador sai 147 | */ 148 | def leave(p:Player){ 149 | _connectionPlayerMap-=p.connId 150 | this._teamList(p.teamId.get)-p 151 | } 152 | /** 153 | * Inicia a proxima rodada 154 | */ 155 | protected def _nextRound(){ 156 | println("NO NEXT ROUND") 157 | display(new Message("Começando uma nova rodada")) 158 | this._currentTeam=this._roundCounter 159 | val p:Player=_teamList(this._currentTeam).getNextPlayer() 160 | //Pega o próximo jogador a falar a palavra 161 | this._roundCounter=(this._roundCounter+1)%this.numTeams 162 | this._currentPlayer=Some(p) 163 | 164 | this._nextPlay() 165 | } 166 | /** 167 | * Achou uma palavra com sucesso definitivamente 168 | */ 169 | def foundWord(){ 170 | 171 | if(_teamList(this._currentTeam).score()==this.maxScore){ 172 | this._endGame(this._currentTeam) 173 | } 174 | else{ 175 | this._nextRound 176 | 177 | } 178 | 179 | } 180 | /** 181 | * @todo implementar 182 | */ 183 | def _endGame(winnerIndex:Int){ 184 | println("FIM DE JOGO") 185 | for(i<-0 until this.numTeams){ 186 | if(i==winnerIndex){ 187 | for(p<-this._teamList(i).getPlayers){ 188 | p.actor ! new Reply(new game.Won("Seu time venceu parabens!")) 189 | } 190 | } 191 | else{ 192 | for(p<-this._teamList(i).getPlayers){ 193 | p.actor ! new Reply(new game.Lost("O time "+winnerIndex+" venceu")) 194 | } 195 | } 196 | } 197 | } 198 | /** 199 | * Falou a palavra Tabu TODOS outros times acertam 200 | */ 201 | def tabu():Unit={ 202 | for(i<-0 until this.numTeams if i!=_currentTeam){ 203 | if(this._teamList(i).score()==this.maxScore){ 204 | this._endGame(i) 205 | return 206 | } 207 | } 208 | this._nextRound 209 | } 210 | override def toString()={ 211 | index+" - "+name 212 | } 213 | 214 | object Status extends Enumeration{ 215 | val WaitingPlayers,Started=Value 216 | } 217 | 218 | override def display(mess:Message){ 219 | var r=new Reply(mess) 220 | for(t<-_teamList){ 221 | 222 | for(p<-t.getPlayers if mess.senderConnId.isEmpty || p.connId!=mess.senderConnId.get){ 223 | p.actor ! r 224 | } 225 | } 226 | } 227 | } 228 | 229 | object Game{ 230 | val minPlayers=2 231 | } --------------------------------------------------------------------------------