Last active
October 2, 2024 09:46
-
-
Save kishida/fa6b220e9e660cc67e8efddd5439c0b8 to your computer and use it in GitHub Desktop.
7並べゲーム
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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> | |
"""); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
bandicam.2024-03-28.07-13-28-465.mp4