投票ゲームの実装
先ほどのジャンケンゲームを発展させ、クライアントのプレイヤー同士が選択した手に応じて勝敗が決まるようにしてみましょう。 ここでは、サーバーは手を選択せず、各クライアントの入力を集計して結果を返すようにします。 通信内容は以下のようになります。
通信方向 | 送信内容 |
---|---|
クライアント→サーバー | プレイヤーが選択した手 |
クライアント←サーバー | ゲームの結果 |
サーバーは、接続されている全てのクライアントから入力を受け取るまで待ち、入力が揃ったらクライアントに対して結果を送信します。 ジャンケンゲームと同じように、ゲームは入力待ち、通信待ち、結果表示の状態を遷移させます。 他のプレイヤーが手を選択している間は通信待ち状態になります。
サーバープログラム
はじめにサーバープログラムです。
serverEvent
と disconnectEvent
で接続されてるクライアントの数を増減させます。
int clientCount = 0;
void serverEvent(Server server, Client client) {
clientCount += 1;
}
void disconnectEvent(Client client) {
clientCount -= 1;
}
clientEvent
で、クライアントから受け取った入力を集計します。
全てのクライアントから入力を受け取り終わると全てのクライアントに対して結果を送信します。
グローバル変数 vote
で3つのボタンのどれが何回選択されたかを数えます。
int[] vote = new int[3];
void clientEvent(Client client) {
int selected = client.read();
println(selected);
vote[selected] += 1;
int sum = 0;
for (int i = 0; i < vote.length; ++i) {
sum += vote[i];
}
if (sum == clientCount) {
int max = 0;
boolean dupplicate = false;
for (int i = 1; i < vote.length; ++i) {
if (vote[i] > vote[max]) {
max = i;
dupplicate = false;
} else if (vote[i] == vote[max]) {
dupplicate = true;
}
}
if (dupplicate) {
printArray(vote);
max = vote.length;
}
server.write(max);
for (int i = 0; i < vote.length; ++i) {
vote[i] = 0;
}
}
}
サーバープログラムの全体は以下のようになります。
import processing.net.*;
Server server;
int clientCount = 0;
int[] vote = new int[3];
void setup() {
server = new Server(this, 5204);
}
void draw() {
}
void clientEvent(Client client) {
int selected = client.read();
println(selected);
vote[selected] += 1;
int sum = 0;
for (int i = 0; i < vote.length; ++i) {
sum += vote[i];
}
if (sum == clientCount) {
int max = 0;
boolean dupplicate = false;
for (int i = 1; i < vote.length; ++i) {
if (vote[i] > vote[max]) {
max = i;
dupplicate = false;
} else if (vote[i] == vote[max]) {
dupplicate = true;
}
}
if (dupplicate) {
printArray(vote);
max = vote.length;
}
server.write(max);
for (int i = 0; i < vote.length; ++i) {
vote[i] = 0;
}
}
}
void serverEvent(Server server, Client client) {
clientCount += 1;
}
void disconnectEvent(Client client) {
clientCount -= 1;
}
クライアントプログラム
次にクライアントプログラムです。 基本的な構造はジャンケンゲームと同様です。
import processing.net.*;
enum Status {
INPUT,
WAIT,
RESULT
}
class Button {
int id, cx, cy, size;
color fillColor;
boolean selected = false;
Button(int id, int cx, int cy, int size, color fillColor) {
this.id = id;
this.cx = cx;
this.cy = cy;
this.size = size;
this.fillColor = fillColor;
}
boolean clicked() {
return dist(mouseX, mouseY, cx, cy) <= size / 2;
}
void draw() {
noStroke();
if (this.selected) {
fill(this.fillColor);
} else {
fill(this.fillColor, 100);
}
ellipse(this.cx, this.cy, this.size, this.size);
fill(0);
textAlign(CENTER, CENTER);
text(this.id, this.cx, this.cy);
}
}
Client client;
Status currentStatus = Status.INPUT;
Button[] buttons;
int result = -1;
void setup() {
size(400, 400);
client = new Client(this, "127.0.0.1", 5204);
int size = 100;
buttons = new Button[3];
buttons[0] = new Button(0, size / 2, height / 2, size, color(255, 0, 0));
buttons[1] = new Button(1, width / 2, height / 2, size, color(0, 255, 0));
buttons[2] = new Button(2, height - size / 2, height / 2, size, color(0, 0, 255));
}
void draw() {
background(255);
boolean win = false;
for (Button button : buttons) {
button.draw();
if (button.selected && result == button.id) {
win = true;
}
}
if (currentStatus == Status.RESULT) {
fill(0);
textAlign(CENTER, CENTER);
if (result == buttons.length) {
text("draw", width / 2, 100);
} else if (win) {
text("win", width / 2, 100);
} else {
text("lose", width / 2, 100);
}
}
}
void mouseClicked() {
if (currentStatus == Status.INPUT) {
int selected = -1;
for (Button button : buttons) {
if (button.clicked()) {
selected = button.id;
button.selected = true;
}
}
if (selected != -1) {
client.write(selected);
currentStatus = Status.WAIT;
}
} else if (currentStatus == Status.RESULT) {
for (Button button : buttons) {
button.selected = false;
}
result = -1;
currentStatus = Status.INPUT;
}
}
void clientEvent(Client client) {
result = client.read();
currentStatus = Status.RESULT;
}