HyleX
May 4, 2026 · View on GitHub
HyleX
A Hyle (Entropy) board game clone
What is this
This is an Entropy / Hyle 7 - like board game clone for Android. Play alone or with friends!
The original game “Entropy” by Eric Solomon requires two game rounds with a swap of roles in between. With HyleX, you can play alone and compete the computer with just one round by choosing a role.
Features:
- Single Play: Compete the computer
- Multiplayer: play against a remote opponent *)
- Privacy: No central server**), no personalised data, no ads, no tracking
- It's FOSS
*) You can also play against friends. Note that there is no central game server. You and your opponent must share your moves via regular messaging apps or QR codes.
**) The app uses App Links to open the app from clicking on such links, which requires a web-domain (https://hx.jepfa.de), to prove integrity of these App Links. The Android OS basically reads this JSON file and verifies that the installed HyleX app is signed with one of the well known containing certificate fingerprints (either by my own or by the one from F-Droid). Otherwise App Links won't open the app and won't perform the opponent's move.
Fore more details, see hylex.jepfa.de.
Screenshots
Show screenshots

Download
Download the app on F-Droid:
Download the app on Google Play Store:
Download the latest test version here for testing: https://hyleX.jepfa.de/hylex.apk Note that you might need to delete the app storage if the app behaves incorrectly! Also, reading old messages could not work after updating.
Implementation
Single play against AI
The AI part is implemented using an optimized Minimax algorithm,see https://en.m.wikipedia.org/wiki/Minimax. It performs up to 4 rounds ahead, limited by the CPU power of the current device.
Multiplayer
Exchanging moves between remote players happen "out-of-band", i.e. there is no central server involved. Instead, moves etc. are encoded as URLs allowing to share and open them directly with the HyleX app. These URLs can be shared through any medium, like messengers, email, QR codes etc. So transport is not handled by this app. Later there is an idea of incorporating Veilid to share these URLs to remote players.
Invitation state transitions
How to read:
Boxes are PlayStates, arrows are allowed transitions. Text on arrows are Operations triggering the transitions.
->Operation means an incoming/received operation from a message.
Operation-> means an outgoing/sent operation from a message.
State model from the perspective of an invitor (initiator of an invitation):
stateDiagram-v2
[*] --> RemoteOpponentInvited: SendInvite->
RemoteOpponentInvited --> RemoteOpponentAccepted_ReadyToMove: ->AcceptInvite
RemoteOpponentInvited --> InvitationRejected: ->RejectInvite
InvitationRejected --> [*]
RemoteOpponentAccepted_ReadyToMove --> WaitForOpponent: Move->
RemoteOpponentAccepted_ReadyToMove --> Resigned: Resign->
ReadyToMove --> WaitForOpponent: Move->
WaitForOpponent --> ReadyToMove: ->Move
ReadyToMove --> Lost: Move->
ReadyToMove --> Won: Move->
ReadyToMove --> FirstGameFinished_WaitForOpponent: Move->
ReadyToMove --> Resigned: Resign->
WaitForOpponent --> Lost: ->Move
WaitForOpponent --> Won: ->Move
WaitForOpponent --> FirstGameFinished_ReadyToSwap: ->Move
WaitForOpponent --> OpponentResigned: ->Resign
FirstGameFinished_ReadyToSwap --> ReadyToMove
FirstGameFinished_WaitForOpponent --> ReadyToMove: ->Move
Lost --> [*]
Won --> [*]
Resigned --> [*]
OpponentResigned --> [*]
State model from the perspective of the invitee (receiver of an invitation):
Invitee has to perform first move:
stateDiagram-v2
[*] --> InvitationPending: ->SendInvite
InvitationPending --> InvitationAccepted_ReadyToMove
InvitationPending --> InvitationRejected: RejectInvite->
InvitationRejected --> [*]
InvitationAccepted_ReadyToMove --> InvitationAccepted_WaitForOpponent: AcceptInvite(with move)->
InvitationAccepted_ReadyToMove --> Resigned: Resign->
ReadyToMove --> WaitForOpponent: Move->
InvitationAccepted_WaitForOpponent --> ReadyToMove: ->Move
WaitForOpponent --> ReadyToMove: ->Move
ReadyToMove --> Lost: Move->
ReadyToMove --> Won: Move->
ReadyToMove --> FirstGameFinished_WaitForOpponent: Move->
ReadyToMove --> Resigned: Resign->
WaitForOpponent --> Lost: ->Move
WaitForOpponent --> Won: ->Move
WaitForOpponent --> FirstGameFinished_ReadyToSwap: ->Move
WaitForOpponent --> OpponentResigned: ->Resign
FirstGameFinished_ReadyToSwap --> ReadyToMove
FirstGameFinished_WaitForOpponent --> ReadyToMove: ->Move
Lost --> [*]
Won --> [*]
Resigned --> [*]
OpponentResigned --> [*]
Invitee has to await first move from invitor:
stateDiagram-v2
[*] --> InvitationPending: ->SendInvite
InvitationPending --> InvitationAccepted_WaitForOpponent: AcceptInvite->
InvitationPending --> InvitationRejected: RejectInvite->
InvitationRejected --> [*]
InvitationAccepted_WaitForOpponent --> ReadyToMove: ->Move
InvitationAccepted_WaitForOpponent --> OpponentResigned: ->Resign
ReadyToMove --> WaitForOpponent: Move->
WaitForOpponent --> ReadyToMove: ->Move
ReadyToMove --> Lost: Move->
ReadyToMove --> Won: Move->
ReadyToMove --> FirstGameFinished_WaitForOpponent: Move->
ReadyToMove --> Resigned: Resign->
WaitForOpponent --> Lost: ->Move
WaitForOpponent --> Won: ->Move
WaitForOpponent --> FirstGameFinished_ReadyToSwap: ->Move
WaitForOpponent --> OpponentResigned: ->Resign
FirstGameFinished_ReadyToSwap --> ReadyToMove
FirstGameFinished_WaitForOpponent --> ReadyToMove: ->Move
Lost --> [*]
Won --> [*]
Resigned --> [*]
OpponentResigned --> [*]
Play state transitions
How to read:
Boxes are PlayStates, arrows are allowed transitions, indicating the direction. Text on arrows are Operations triggering the transitions.
Sequence flow if an invitation gets rejected:
sequenceDiagram
actor Local as Invitor
actor Remote as Invitee
Local->>+Remote: <SendInvite>
Note over Local: [RemoteOpponentInvited]
Note over Remote: [InvitationPending]
Remote-->>-Local: <RejectInvite>
Note over Local: [InvitationRejected]
Note over Remote: [InvitationRejected]
Sequence flow if an invitation gets accepted:
sequenceDiagram
actor Local as Invitor
actor Remote as Invitee
Local->>+Remote: <SendInvite>
Note over Local: [RemoteOpponentInvited]
Note over Remote: [InvitationPending]
alt Invitor starts
Remote-->>-Local: <AcceptInvite>
Note over Remote: [InvitationAccepted_WaitForOpponent]
Note over Local: [RemoteOpponentAccepted_ReadyToMove]
else Invitee starts with initial move
Note over Remote: [InvitationAccepted_ReadyToMove]
Remote-->>Local: <AcceptInvite with Move>
Note over Remote: [InvitationAccepted_WaitForOpponent]
Note over Local: [RemoteOpponentAccepted_ReadyToMove]
end
loop actual play
Local->>+Remote: <Move>
Note over Local: [WaitForOpponent]
Note over Remote: [ReadyToMove]
Remote->>-Local: <Move>
Note over Remote: [WaitForOpponent]
Note over Local: [ReadyToMove]
end
License
HyleX / Hyle X - An Entropy clone
Copyright (C) 2026 Jens Pfahl
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

