Der Zweck der Lektion
Heute werden wir ein Netzwerkkartenspiel für zwei Spieler schreiben. Welches Spiel soll ich schreiben? Schreiben wir ein beliebtes Kartenspiel "Fool", dessen Zweck es ist, alle Karten loszuwerden. Hier erfahren Sie mehr über die Regeln .

Bild 1.
Ein bisschen Theorie
— RS-232, , , . "", , . RS-232, M5STACK TTL.
RS-232 "0" -3 -25 , "1" +3 +25 . RS-232 TTL "0" 0 , "1" , 3.3 5 (. 2).

2. RS-232 TTL
M5STACK / R0, R2 (RX) T0, T2 (TX) (. 3), USB . , , 0 1 .

3.
Serial Arduino IDE https://www.arduino.cc/reference/en/language/functions/communication/serial/
ASCII, : https://en.wikipedia.org/wiki/ASCII
- M5STACK (2 .);
- USB-C (2 .);
- .
!
1. —
, . , MS Office Word Paint (. 4).

4. MS Office Word Paint :)
1.2.1 http://forum.m5stack.com/topic/49/lesson-1-2-1-lcd-how-to-create-image-array logo.c, .
extern unsigned char logo[];
2.
, 36 . 6 . 12 . 10 , . , 7. : ( — ; ; ; ) : , , , , . , . (. 5).

5.
define playerAmount 6
#define fullAmount 36
#define playerFieldAmount 10
#define gameFieldAmount 6
struct playCard
{
int card;
int suit;
int color;
int property = -1; // -2 not avaiable, -1 free, 0 trump, 1 player #1, 2 player #2
int field; // + player field, - game field
};
String cards[9] = {"6", "7", "8", "9", "10", "J", "Q", "K", "A"};
char suits[4] = {3, 4, 5, 6}; // , , ,
int colors[2] = {0xe8e4, 0x00}; // red, black
playCard deckCards[fullAmount];
3.
. 1. , , (. 5.1):

5.1.
if ((opponentSteps == playerSteps) && (playerSteps == 0))
{
deckCards[selectedCard].field = -1;
sync();
}
. 2. , , (. 5.2) , :

5.1.
else if (opponentSteps > playerSteps)
{
if ((((deckCards[selectedCard].card > deckCards[pfCardId].card) && (deckCards[selectedCard].suit == deckCards[pfCardId].suit)) || ((deckCards[selectedCard].suit == trumpSuit) && (deckCards[pfCardId].suit != trumpSuit))))
{
deckCards[selectedCard].field = -opponentSteps;
sync();
}
}
. 3. , , :
else if (opponentSteps == playerSteps)
{
for (int i = 0; i < fullAmount; i++)
{
if ((deckCards[selectedCard].card == deckCards[i].card) && (deckCards[i].field < 0) && (deckCards[i].property != -2))
{
deckCards[selectedCard].field = -(playerSteps + 1);
sync();
break;
}
}
}
/. 1. , :
if (opponentSteps == playerSteps) //
{
for (int i = 0; i < fullAmount; i++)
{
if (deckCards[i].field < 0)
{
deckCards[i].property = -2;
}
}
}
/. 2. , , :
else if (opponentSteps > playerSteps) //
{
for (int i = 0; i < fullAmount; i++)
{
if ((deckCards[i].field < 0) && (deckCards[i].property != -2))
{
addPlayerCard(playerId, i);
}
}
}
4.
M5STACK, .
void drawCard(int x, int y, playCard card) {
M5.Lcd.fillRoundRect(x, y, 30, 50, 5, 0xffff);
M5.Lcd.drawRoundRect(x, y, 30, 50, 5, 0x00);
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(colors[card.color]);
M5.Lcd.setCursor((x + 3), (y + 6));
M5.Lcd.print(cards[card.card]);
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor((x + 8), (y + 24));
M5.Lcd.print(suits[card.suit]);
}
void drawEmptyCard(int x, int y) {
M5.Lcd.fillRect(x, y, 30, 50, 0x2589);
M5.Lcd.drawRoundRect(x, y, 30, 50, 5, 0x00);
}
Windows: Alt 3 6, .
5.
void drawSelect(playCard card) {
int n = card.field - 1;
int x = 10 + (n * 30);
int y = (yPlayerField - 10);
drawEmptyCard(x, yPlayerField);
drawCard(x, y, card);
}
void clearSelect(playCard card) {
int n = card.field - 1;
int x = 10 + (n * 30);
int y = (yPlayerField - 10);
M5.Lcd.fillRect(x, y, 30, 50, 0x2589);
drawCard(x, yPlayerField, card);
}
6.
void drawGameTable() {
M5.Lcd.fillScreen(0x2589); // green table
drawAllFields();
}
void drawMenu() {
M5.Lcd.fillRect(0, 0, 320, 20, 0x00); // score bar
M5.Lcd.fillRect(0, 220, 320, 20, 0x00); // menu bar
/* menu buttons */
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(0x7bef);
M5.Lcd.setCursor(62, 223);
M5.Lcd.print("G");
M5.Lcd.setCursor(155, 223);
M5.Lcd.print("A");
M5.Lcd.setCursor(247, 223);
M5.Lcd.print("S");
}
7.
void updateGraphics() {
drawGameTable();
drawMenu();
drawPlayerId();
drawRest();
for (int i = 0; i < fullAmount; i++)
{
if (deckCards[i].property == playerId)
{
if (deckCards[i].field > 0) // if in the hands of
drawPlayerCard(deckCards[i]);
else // if in the playing field
drawPlPfCard(deckCards[i]);
}
else if (deckCards[i].property == getOpponentId())
{
if (deckCards[i].field < 0)
drawOpPfCard(deckCards[i]); // draw opponent's cards in the playing field
}
else if (deckCards[i].property == 0)
{
drawTrumpCard(deckCards[i]);
}
}
}
(, drawPlayerId()) ;)
8. /

5.3
. , . , true false.
bool serialWriteStr(String str) {
Serial.print(str);
Serial.print('\n');
String input = serialReadStr();
if (input != "")
{
if (input[0] == (char)0x04) return true;
}
return false;
}
timeout (3000 ) , . .
String serialReadStr() {
String buf = "";
long timeout = 3000;
long previousMillis = millis();
while (true)
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > timeout) break;
if (Serial.available() > 0)
{
char chr = (char)Serial.read();
if ((chr != (char)0x16) && (chr != (char)0x04) && (buf == "")) // clear trash
{
Serial.read();
}
else
{
if (chr == '\n')
break;
else
buf += chr;
}
}
}
if (buf != "")
{
Serial.print((char)0x04);
Serial.print('\n');
}
return buf;
}
9.
, , (. 6). , , . (parseString), , ( Split JS).

6.
bool serialRecivePacket() {
String input = serialReadStr();
if (input.length() > 0)
{
if ((char)input[0] == (char)0x16)
{
input[0] = ' ';
char groupType = ((parseString(0, (char)0x1d, input)).toInt()) + '0';
String groupData = parseString(1, (char)0x1d, input);
int groupDataLenmo = (groupData.length() - 1);
if (groupData[groupDataLenmo] == (char)0x03)
{
groupData[groupDataLenmo] = ' ';
if (groupType == (char)0x31) updateReciveDeckCards(groupData);
else if (groupType == (char)0x32) playerId = 2;
return true;
}
}
return false;
}
}
String parseString(int idSeparator, char separator, String str) { // like split JS
String output = "";
int separatorCout = 0;
for (int i = 0; i < str.length(); i++)
{
if ((char)str[i] == separator)
{
separatorCout++;
}
else
{
if (separatorCout == idSeparator)
{
output += (char)str[i];
}
else if (separatorCout > idSeparator)
{
break;
}
}
return output;
}
parseString:
parseString(1, ':', "cat:Bob,Jack:dog:Martin,Kelvin"); -----> Bob,Jack
parseString(0, ',', "Bob,Jack"); -----> Bob
parseString(1, ',', "Bob,Jack"); -----> Jack
10.
, , , , " !" (. 7). - . , " !" 2.

7.
void handshakePlayerId() {
long tpid = random(10, 1001) * 10;
long previousMillis = millis();
while (!serialRecivePacket())
{
unsigned long currentMillis = millis();
if (currentMillis — previousMillis > tpid) break;
}
while (!serialSendPlayerTId());
}
bool serialSendPlayerTId() {
String str = "";
str += (char)0x16;
str += (char)0x32; // type "player id selector"
str += (char)0x1d;
str += (char)0x03;
return serialWriteStr(str);
}
11.
bool serialSendDeckCards() {
String str = "";
str += (char)0x16;
str += (char)0x31; // type "card transfer flag"
str += (char)0x1d;
for (int i = 0; i < fullAmount; i++)
{
str += (char)0x1e;
str += deckCards[i].card;
str += (char)0x1f;
str += deckCards[i].suit;
str += (char)0x1f;
str += deckCards[i].color;
str += (char)0x1f;
str += deckCards[i].property;
str += (char)0x1f;
str += deckCards[i].field;
}
str += (char)0x03;
return serialWriteStr(str);
}
void updateReciveDeckCards(String groupData) {
for (int i = 0; i < fullAmount; i++)
{
/* update new card */
String record = parseString(i, (char)0x1e, groupData);
deckCards[i].card = (int8_t)(parseString(0, (char)0x1f, record).toInt());
deckCards[i].suit = (int8_t)(parseString(1, (char)0x1f, record).toInt());
deckCards[i].color = (int8_t)(parseString(2, (char)0x1f, record).toInt());
deckCards[i].property = (int8_t)(parseString(3, (char)0x1f, record).toInt());
deckCards[i].field = (int8_t)(parseString(4, (char)0x1f, record).toInt());
}
getTrumpCard();
updateGraphics();
checkWinner();
}
(, getTrumpCard()) ;)
12.
. . loop(). . .
void sync(bool auto_ = false) {
if (queue != playerId)
{
while (!serialRecivePacket());
queue = playerId;
}
else
{
if (!auto_)
{
while (!serialSendDeckCards());
updateGraphics();
checkWinner();
queue = getOpponentId();
}
}
}
13. ?
whoWin() , -1, .
, , . 10 (playerFieldAmount) , .
int whoWin() {
int opponentId = getOpponentId();
int playerAmount_ = getAmount(playerId);
int opponentAmount = getAmount(opponentId);
if ((playerAmount_ == 0) || (opponentAmount >= playerFieldAmount)) return playerId;
if ((opponentAmount == 0) || (playerAmount_ >= playerFieldAmount)) return opponentId;
return -1;
}
void checkWinner() {
int winner = whoWin();
if (winner != -1) drawWinnerShow(winner);
}
14.
: , beta-, . !
Arduino IDE .
15.
(. 5.1). (. 8). ! (. 8.1).

8.

8.1. !
\
M5Stack