I started this Rust project days ago before my assignment for
computer networks was due. And also, I though that I shall practice
coding after reading half through the book Programming
Rust by Jim Blandy, Jason Orendorff. Then the snake was born out of
nowhere.
The project is build for personal practice, especially around
networks and rust features. Nevertheless, We shall consider if someone
would acually play it, right? Or a step forward, if somebody would learn
from the project? Thus I write this blog in case of oblivion.
The structure of the project
Everything starts from a easy ground. For building a local version of
the game, while considering that it may be migrated to a networked
version, we implements a Client thread and a
Server thread. The Client thread is
responsible for listening a keyboard action, and convert then into a
Ctrl signal (which is a enum type), and send
it to the Server with a std::mpsc channel; The
Server thread will host an instance of the game
(YardSim), and push the screen buffer YardBuf
(which is a Vec<Vec<TUIBlock>>) to the
Client, who is in charge of rendering the game.
graph TB
subgraph Client
Renderer(Render)
Keyboard(KeyboarCtrlListener)
end
subgraph Server
YardSim(YardSim)--BufferPipe-->Renderer
Keyboard--CtrlPipe-->YardSim
end
Moreover, to implement the multiplayer game via network, we shall
develop more modules. The ServerWrapper thread consists the
Server thread, so do the ClientWrapper do.
graph TB
subgraph ClientWrapper1
subgraph Client
Renderer(Render)
Keyboard(KeyboarCtrlListener)
end
Keyboard--CtrlPipe-->TCPSocket1(TCPSocket)
UDPSocket1(UDPSocket)--BufferPipe-->Renderer
end
subgraph ClientWrapper2
TCPSocket2(TCPSocket)
UDPSocket2(UDPSocket)
end
subgraph ClientWrapperN
TCPSocketN(TCPSocket)
UDPSocketN(UDPSocket)
end
subgraph ServerWrapper
TCPSocket1-.Connect.-TCPListener(TCPListener)
TCPSocket2-.Connect.-TCPListener
TCPSocketN-.Connect.-TCPListener
TCPListener-.FireUp.-ClientHandler1
TCPListener-.FireUp.-ClientHandler2
TCPListener-.FireUp.-ClientHandlerN
TCPSocket1==TCPStream==>ClientHandler1
TCPSocket2==TCPStream==>ClientHandler2
TCPSocketN==TCPStream==>ClientHandlerN
ClientHandler1[ClientHandler1]--CtrlPipe-->YardSim
ClientHandler2[ClientHandler2]--CtrlPipe-->YardSim
ClientHandlerN[ClientHandlerN]--CtrlPipe-->YardSim
subgraph Server
YardSim(YardSim)
end
ServerUDPSocket(UDPSocket Multicast)==Buffer==>UDPSocket1
ServerUDPSocket==Buffer==>UDPSocket2
ServerUDPSocket==Buffer==>UDPSocketN
YardSim--BufferPipe-->ServerUDPSocket
end
Today we virtually participated the regional of 2018 Nanjing, and I
have done my first non-trivial string problem, introducing a new
algorithm called Extended-KMP. Thus I bet it notable on by blog.
Problem Statement
Given two strings s and t, count the number of tuples \((i, j, k)\) such that
\(1\le i\le j\le |s|\)
\(1\le k\le |t|\)
\(j − i + 1 > k\)
The \(i\)-th character of \(s\) to the \(j\)-th character of \(s\), concatenated with the first character
of \(t\) to the \(k\)-th character of \(t\), is a palindrome.
\(2\le |s|\le 10^6\), \(1\le |t|<|s|\)
Solution
The problem is to find and count the number of cases that there is
two adjacent substrings \(s^{(1)}\),
\(s^{(2)}\) in \(s\) and another \(t^{(1)}\) in \(t\), provided that \(s^{(2)}\) is a palindrome, and \(s^{(1)}\) is reversely matched with \(t^{(1)}\).
So let's reverse the string \(s\).
Then use the famous Manacher algorithm on \(s\) (when there is a longest palindrome
\(s_x\cdots s_y\), let \(p_{x+y}=\lfloor(y-x+1)/2\rfloor\)) and
count every occurrence centered at \(i=\lceil(x+y)/2\rceil\).
Let \(s^j\) be the suffix of \(s\) starting from \(j\). We should firstly find the longest
common prefix of suffix \(s^j\) and
\(t\), and sum up the length of these
prefixes around \(i\). Precisely, all
of the prefixes starting from \(i+1\)
to \(i+p_{x+y}\) should be counted.
Using prefix sum, we could get that value in \(O(1)\) at every symmetrical center.
It must be noted that \(j-i+1>k\), then \(s_2\) must not be empty.
Dealing with bounds and indexes of strings is tricky, so be
careful.