Skip to content

Instantly share code, notes, and snippets.

@kishida
Last active March 29, 2024 01:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kishida/fa6b220e9e660cc67e8efddd5439c0b8 to your computer and use it in GitHub Desktop.
Save kishida/fa6b220e9e660cc67e8efddd5439c0b8 to your computer and use it in GitHub Desktop.
7並べゲーム
/*
* to run, use Java 22 or later
* java --enable-preview --source 22 SevenGame.java
*/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Gatherers;
public class SevenGame {
/** カードのスート */
enum Suit {
Spade("spades", "black", "♠"),
Club("clubs", "black", "♧"),
Diamond("diams", "red", "♢"),
Heart("hearts", "red", "♡");
String mark;
String color;
String character;
Suit(String mark, String color, String character) {
this.mark = mark;
this.color = color;
this.character = character;
}
}
/** カード */
static String cardToHTML(Suit suit, int number) {
return "<span style='color: %s'>&%s;%s</span>"
.formatted(suit.color, suit.mark, numChar(number));
}
static String numChar(int n) {
return switch(n) {
case 1 -> "A";
case 11 -> "J";
case 12 -> "Q";
case 13 -> "K";
default -> n + "";
};
}
record Card(Suit suit, int number) implements Comparable<Card>{
String toHTML() {
return cardToHTML(suit, number);
}
public String toString() {
return "%s%s".formatted(suit.character, numChar(number));
}
@Override
public int compareTo(Card o) {
if (o.suit() != suit) {
return suit.compareTo(o.suit);
}
return number - o.number;
}
}
/** すべてのカード */
List<Card> allCards() {
return Arrays.stream(Suit.values())
.flatMap(s -> IntStream.rangeClosed(1, 13).boxed()
.map(n -> new Card(s, n)))
.toList();
}
/** カードを配る */
List<? extends List<Card>> dest(int members) {
var cards = new ArrayList<>(allCards());
Collections.shuffle(cards);
return cards.stream()
.gather(Gatherers.windowFixed((cards.size() - 1) / members + 1))
.map(l -> l.stream().sorted().collect(Collectors.toCollection(ArrayList::new)))
.toList();
}
static class Range {
int first, last;
Range() {
first = last = 7;
}
boolean includes(int num) {
return num >= first && num <= last;
}
boolean isDisposal(int num) {
return num < 7 ? num == first - 1 : num == last + 1;
}
}
void main() throws Exception {
// 手札
var hands = dest(3);
// 場
Map<Suit, Range> stage = Arrays.stream(Suit.values())
.collect(Collectors.toMap(Function.identity(), _ -> new Range()));
// 手番のプレイヤー
var player = -1;
// 7を場に出す
for (List<Card> cards : hands) {
for(var ite = cards.iterator(); ite.hasNext(); ) {
var card = ite.next();
if (card.number != 7) continue;
ite.remove();
}
}
// サーバーを起動
var server = new ServerSocket(80);
System.out.println("Seven game server start");
for (;;) {
try(var soc = server.accept();
var isr = new InputStreamReader(soc.getInputStream());
var bur = new BufferedReader(isr);
var w = new PrintWriter(soc.getOutputStream(), false,
Charset.forName("utf-8")))
{
String req = bur.readLine();
if (req == null) continue;
//ヘッダを捨てる
while (!bur.readLine().isEmpty()) {}
// URLになにかあればゲーム操作
var param = req.split(" ")[1];
if (!param.equals("/")) {
try {
int n = Integer.parseInt(param.substring(1));
var card = hands.get(player).remove(n);
if (card.number < 7) {
stage.get(card.suit).first = card.number;
} else {
stage.get(card.suit).last = card.number;
}
} catch (NumberFormatException _) {}
}
// レスポンスを返す
w.println("""
HTTP/1.1 200
content-type: text/html; charset=utf-8
<html><head><title>7並べ</title>
</head>
<body><h1>7並べ</h1>
""");
// 場札の表示
w.println("<table>");
for (var suit : Suit.values()) {
w.println("<tr>");
var row = stage.get(suit);
for (int i = 1; i <= 13; ++i) {
w.println("<td>" + (row.includes(i) ? cardToHTML(suit, i) : ""));
}
w.println("</tr>");
}
w.println("</table>");
if (hands.stream().allMatch(List::isEmpty)) {
// ゲーム終了
w.println("Finish!!!");
} else {
// 手番を進める
do {
player = (player + 1) % hands.size();
} while (hands.get(player).isEmpty() ||
hands.get(player).stream()
.noneMatch(c -> stage.get(c.suit).isDisposal(c.number)));
// 手札の表示
w.println("""
<h2>Players</h2>
<table>""");
for (int i = 0; i < hands.size(); ++i) {
boolean playing = i == player;
w.println(STR."<tr><td>\{playing ? ">" : ""}</td><td>[player \{i + 1}]</td>");
var cards = hands.get(i);
for (int j = 0; j < cards.size(); ++j) {
Card c = cards.get(j);
w.print("<td>" + c.toHTML());
if (playing && stage.get(c.suit).isDisposal(c.number)) {
w.print(STR."<a href='/\{j}'>put</a>");
}
w.println("</td>");
}
w.println("</tr>");
}
w.println("</table>");
}
w.println("""
</body></html>
""");
}
}
}
}
@kishida
Copy link
Author

kishida commented Mar 27, 2024

bandicam.2024-03-28.07-13-28-465.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment