Campeonato de Gamão 1. Regras O campeonato de gamão será disputado de acordo com as regras tradicionais do jogo, facilmente encontradas na Internet. As duas cores tradicionais das pedras do jogo serão representadas por X e O, de modo que um jogador jogará com as pedras X e o outro com as pedras O. Por convenção, o jogador X sempre inicia o jogo, fazendo a primeira jogada. Cada equipe deverá trazer um computador, dotado de placa de rede Ethernet e podendo ser configurado manualmente para um endereço IP fixado. Uma vez iniciada a partida, o jogo deverá se desenrolar de forma totalmente autônoma (sem interferência humana via teclado, mouse, etc.). As máquinas das equipes (clientes) deverão se conectar a uma máquina servidora, sob a responsabilidade da organização do campeonato, de acordo com o protocolo especificado nesta regra. O estado atual do jogo é mantido pelo servidor e comunicado aos clientes, com a periodicidade e o formato especificados. As máquinas cliente deverão levar em conta este estado para decidir sobre as ações a serem tomadas. Estas ações devem ser comunicadas ao servidor, também seguindo o protocolo padrão. As ações dos jogadores alteram o estado do jogo, que é calculado pelo servidor e informado aos clientes, iniciando um novo ciclo. As equipes podem utilizar qualquer técnica ou algoritmo que desejarem para resolver o problema. Há limitações quanto à utilização de uma única máquina por equipe e ao tempo máximo das jogadas. Cada equipe não deve exceder o tempo máximo de 60 (sessenta) segundos nem o tempo médio máximo de 30 (trinta) segundos para cálculo das jogadas. Estes tempos serão cronometrados pelo árbitro das partidas, admitindo-se ligeiras tolerâncias a critério do árbitro. Em caso de ser excedido o tempo máximo de uma jogada, o árbitro informará ao servidor para efetuar a primeira jogada possível para a equipe. Caso não seja respeitado o tempo médio máximo, ao final da partida a equipe será considera perdedora. O formato de disputa dos Campeonatos (todos contra todos, grupos, eliminatório, etc.) será definido em função do número de inscritos e divulgado posteriormente (pouco antes do início do Campeonato). 2. Servidor
Um programa servidor se comunicará com os programas clientes das equipes. As equipes não precisam nem podem desenvolver ou alterar o programa servidor, que é detalhado apenas para que as equipes possam testar seus programas cliente. A comunicação entre o servidor e os clientes se encarregará das seguintes ações: informar o cliente sobre o estado atual do jogo (posição das pedras e valor dos dados); comunicar ao cliente as jogadas do adversário; receber do cliente a informação sobre as suas jogadas. A comunicação entre o servidor e os clientes é feita via rede, usando sockets TCP (orientados a conexão). A conexão com os sockets se dá nas portas 3123 (para a equipe que joga com as pedras X ) e 3124 (pedras O ). O protocolo inicial de comunicação é o seguinte: São abertos pelo servidor dois sockets TCP, nas portas 3123 e 3124, que passam a esperar por conexões. O servidor aceita no máximo uma conexão em cada porta. O jogo se inicia apenas quando estiverem estabelecidas conexões nas duas portas. Uma vez que os dois times estejam conectados, a cada jogada o servidor repete o seguinte procedimento, até que uma das equipes vença a disputa: São sorteados aleatoriamente os valores dos dois dados. O servidor envia para os dois jogadores (independentemente de qual jogador está na vez de jogar) o estado atual do jogo. Este estado é descrito pela estrutura de dados do tipo ESTADO (detalhada a seguir) e contém a configuração das pedras, o valor dos dados e qual jogador está na vez de jogar. O servidor espera que o jogador da vez envie a sua jogada, em uma estrutura de dados do tipo JOGADA (detalhada a seguir). A jogada recebida é transmitida ao outro jogador (também em uma JOGADA) e executada, modificando o estado corrente do jogo. 3. Cliente Cada equipe deverá desenvolver seu próprio programa cliente, que conterá a sua estratégia de jogo. O algoritmo inicial a ser seguido é o seguinte: O programa pergunta ao usuário: o endereço IP ou nome da máquina onde está rodando o programa servidor; e com quais pedras o usuário vai jogar ('X' ou 'O'). Com estas informações, o cliente deve se conectar à porta adequada (3123 ou 3124) na máquina onde está rodando o servidor. Sendo estabelecida a conexão, o programa cliente passa a executar o seguinte procedimento, até que uma das equipes vença a disputa:
Espera que o servidor envie o estado do jogo (tipo ESTADO). É a vez do adversário jogar? Se sim, espera que o servidor envie a jogada dele (tipo JOGADA). Se não (ou seja, se for a minha vez de jogar), calcula a jogada mais adequada para esta configuração do jogo e a envia para o servidor (tipo JOGADA). Executa a jogada, modificando o estado do jogo. 4. As estruturas de dados A comunicação entre servidor e cliente envolve as estruturas de dados ESTADO e JOGADA. O conteúdo destas estruturas é detalhado a seguir, utilizando uma sintaxe inspirada em C. 4.1. A estrutura ESTADO ESTADO: int c[26]; // Pedras na casa: >0 jogador X <0 jogador O // As casas de 1 a 24 correspondem às casas reais // A casa 0 é o "inferno" do jogador X // A casa 25 é o "inferno" do jogador O int d[2]; // O resultado dos dois dados bool jx; // É a vez do jogador X? A estrutura ESTADO é composta por um vetor de 26 inteiros (denominado c), um outro vetor de 2 inteiros (denominado d) e um booleano jx (ou seja, mais um inteiro). Cada elemento do vetor c representa o número de pedras em uma das casas do tabuleiro. Convencionou-se que um número positivo n indica que a casa correspondente está ocupada por n pedras 'X', enquanto que um número negativo -n indica que a casa está ocupada por n pedras 'O'. O número c[1] corresponde à casa do canto superior esquerdo do tabuleiro, c[12] ao canto superior direito, c[13] ao canto inferior direito e c[24] ao canto inferior esquerdo. As pedras 'X' se movem na direção dos índices crescentes (ou seja, da casa 1 para a casa 24), enquanto que as pedras 'O' se movem no sentido contrário (da casa 24 para a casa 1). Note-se que, enquanto o tabuleiro real tem 24 casas, o vetor c tem 26 números. O primeiro (c[0] na notação C) e o último (c[25] na notação C) números correspondem a casas virtuais que são ocupadas por pedras fora do tabuleiro. Para exemplificar, se o jogador 'X está com 3 pedras fora do tabuleiro e o jogador 'O com 2, tem-se c[0] igual a 3 e c[25] igual a -2. O vetor d contém os valores sorteados para os dois dados (dois números inteiros de 1 a 6).
Finalmente, o booleano jx é um inteiro que contém FALSE (ou seja, um valor zero) se não for a vez do jogador 'X' jogar (sendo conseqüentemente a vez do jogador 'O') e TRUE (ou seja, um valor diferente de zero) se for a vez do jogador 'X' jogar. 4.2. A estrutura JOGADA MOVIMENTO: bool d0; // Jogar com o dado 0? int c; // Casa a jogar JOGADA: MOVIMENTO jog[4]; A estrutura JOGADA é composta por um vetor (denominado jog) de 4 dados do tipo MOVI- MENTO. Cada um destes elementos de jog representa um dos movimentos a serem efetuados. O vetor é de 4 elementos porque a regra do gamão prevê que, ao serem sorteados dados dobrados (1 e 1, 3 e 3, 6 e 6, etc.), o jogador tem direito de efetuar quatro movimentos, como se existissem 4 dados e não apenas 2. Quando os dados não forem dobrados, os dois últimos elementos de jog (jog[2] e jog[3]) devem ser desconsiderados pelos programas. Cada MOVIMENTO é composta de um booleano d0 e um inteiro c. O inteiro c indica a casa com a qual se quer fazer o movimento (um número de 0 a 25), enquanto que o booleano d0 indica se o movimento deve ser feito com o número de pontos do primeiro dado (TRUE) ou do segundo dado (FALSE). O primeiro dado corresponde a d[0] na estrutura ESTADO e o segundo dado, a d[1]. 5. Os programas Para facilitar o desenvolvimento dos programas pelas equipes, estão sendo postos à disposição um programa servidor e um modelo de programa cliente. Ambos os programas estão desenvolvidos em C++ para sistema operacional Linux, mas podem ser facilmente portados para outras linguagens orientadas a objeto e outros sistemas operacionais. Todas as funcionalidades mais imporrtantes para o desenvolvimento dos programas são fornecidas por uma classe GAMAO, que é independente de sistema operacional. Como se trata de C++ padrão, a dependência do sistema operacional se deve unicamente à biblioteca utilizada para impressão em tela. Foi utilizada a biblioteca padrão do Linux curses, que faz impresão formatada em modo texto. Os programas não usam nenhuma biblioteca gráfica para interfaceamento com o usuário. Todas as funcionalidades de interfacea-
mento com o usuário estão condensadas em uma classe TELA, que pode ser reescrita para se adequar ao ambiente desejado pela equipe. Há também uma classe SOCKET que implementa as funcionalidades de base de comunicação via rede, que eventualmente precisa ser adaptada caso se use outra linguagem ou outro sistema operacional. O programa servidor implementa todas as funcionalidades necessárias, correspondendo essencialmente ao programa que será utilizado durante o campeonato (exceto pela forma de visualização). O programa cliente tem todas as funcionalidades de comunicação com o servidor e se baseia na função calcula_jogada da classe GAMAO para escolher a jogada mais apropriada à situação do jogo. A função calcula_jogada é a parte central do programa cliente, e deverá implementar a estratégia de jogo da equipe. No modelo proposto (que não necessariamente precisa ser adotado), é seguido o seguinte algoritmo: Geram-se todas as possíveis jogadas para a configuração atual do jogo. Para cada uma destas jogadas: Efetuam-se os movimentos da jogada, obtendo-se o tabuleiro resultante da aplicação daquela jogada. Dá-se uma nota ao tabuleiro resultante. A nota varia entre +1 e -1. Uma nota +1 indica que o tabuleiro resultante é 100% favorável ao jogador 'X', ou seja, ele venceu o jogo. Uma nota -1 indica um tabuleiro 100% favorável ao jogador 'O'. Uma nota 0 indica um tabuleiro perfeitamente equilibrado entre os dois jogadores. Notas positivas indicam tabuleiros mais favoráveis ao 'X' que ao 'O', enquanto notas negativas sinalizam um tabuleiro melhor para o 'O' que para o 'X'. Uma vez analisadas todas as jogadas, adota-se a jogada mais favorável ao jogador da vez, ou seja, a jogada que gerou o tabuleiro com maior nota se for a vez do jogador 'X' ou o de menor nota se for a vez do 'O'. A nota gerada pela classe GAMAO do programa modelo é simplesmente um número aleatório entre +1 e -1, de modo que o programa cliente escolhe de forma aleatória uma das possíveis jogadas para executar. As equipes podem introduzir uma forma mais inteligente de dar a nota a um tabuleiro ou reescrever completamente a função calcula_jogada. 5.1. Instalação e utilização dos programas 1. Obtenha o arquivo gamao.tar, disponível em ftp://ftp.dca.ufrn.br/cbrn2005/gamao.tgz e descompacte-o. No Windows, basta utilizar qualquer dos programas clássicos de descompactação. No Linux: > cd PASTA_ONDE_FOI_SALVO_O_ARQUIVO > tar xvfz gamao.tgz > cd gamao
2. No Windows, faça as adaptações necessárias no código e compile-o usando seu compilador preferido. No Linux, execute: > make 3. Execute o programa servidor. No Linux, abra um terminal de comandos, vá para o diretório gamao e execute: >./servidor 4. Execute duas instâncias do programa cliente, que podem estar na mesma máquina ou em máquinas diferentes. No Linux, abra um terminal de comandos para cada instância, vá para o diretório gamao e execute: >./cliente SERVIDOR onde SERVIDOR é o nome ou endereço IP da máquina onde está rodando o servidor. Em uma das instâncias, escolha jogar com as pedras 'X'; na outra, com as pedras 'O'. O programa cliente permite jogar no modo automático, que é o que deve ser utilizado durante a competição, ou no modo manual, onde as jogadas são escolhidas pelo usuário.