Organizes Chess class and common tags
This commit is contained in:
@@ -20,11 +20,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.model.nip64Chess
|
package com.vitorpamplona.amethyst.model.nip64Chess
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
|
||||||
import com.vitorpamplona.quartz.nip64Chess.Color
|
import com.vitorpamplona.quartz.nip64Chess.Color
|
||||||
import com.vitorpamplona.quartz.nip64Chess.GameResult
|
import com.vitorpamplona.quartz.nip64Chess.GameResult
|
||||||
import com.vitorpamplona.quartz.nip64Chess.GameTermination
|
import com.vitorpamplona.quartz.nip64Chess.GameTermination
|
||||||
import com.vitorpamplona.quartz.nip64Chess.accept.LiveChessGameAcceptEvent
|
import com.vitorpamplona.quartz.nip64Chess.accept.LiveChessGameAcceptEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
import com.vitorpamplona.quartz.nip64Chess.challenge.LiveChessGameChallengeEvent
|
import com.vitorpamplona.quartz.nip64Chess.challenge.LiveChessGameChallengeEvent
|
||||||
import com.vitorpamplona.quartz.nip64Chess.end.LiveChessGameEndEvent
|
import com.vitorpamplona.quartz.nip64Chess.end.LiveChessGameEndEvent
|
||||||
import com.vitorpamplona.quartz.nip64Chess.move.LiveChessMoveEvent
|
import com.vitorpamplona.quartz.nip64Chess.move.LiveChessMoveEvent
|
||||||
@@ -46,7 +48,7 @@ class ChessAction {
|
|||||||
suspend fun createChallenge(
|
suspend fun createChallenge(
|
||||||
gameId: String,
|
gameId: String,
|
||||||
playerColor: Color,
|
playerColor: Color,
|
||||||
opponentPubkey: String? = null,
|
opponent: OpponentTag? = null,
|
||||||
timeControl: String? = null,
|
timeControl: String? = null,
|
||||||
signer: NostrSigner,
|
signer: NostrSigner,
|
||||||
): LiveChessGameChallengeEvent =
|
): LiveChessGameChallengeEvent =
|
||||||
@@ -54,7 +56,7 @@ class ChessAction {
|
|||||||
LiveChessGameChallengeEvent.build(
|
LiveChessGameChallengeEvent.build(
|
||||||
gameId = gameId,
|
gameId = gameId,
|
||||||
playerColor = playerColor,
|
playerColor = playerColor,
|
||||||
opponentPubkey = opponentPubkey,
|
opponent = opponent,
|
||||||
timeControl = timeControl,
|
timeControl = timeControl,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -69,15 +71,13 @@ class ChessAction {
|
|||||||
*/
|
*/
|
||||||
suspend fun acceptChallenge(
|
suspend fun acceptChallenge(
|
||||||
gameId: String,
|
gameId: String,
|
||||||
challengeEventId: String,
|
challengeEvent: EventHintBundle<LiveChessGameChallengeEvent>,
|
||||||
challengerPubkey: String,
|
|
||||||
signer: NostrSigner,
|
signer: NostrSigner,
|
||||||
): LiveChessGameAcceptEvent =
|
): LiveChessGameAcceptEvent =
|
||||||
signer.sign(
|
signer.sign(
|
||||||
LiveChessGameAcceptEvent.build(
|
LiveChessGameAcceptEvent.build(
|
||||||
gameId = gameId,
|
gameId = gameId,
|
||||||
challengeEventId = challengeEventId,
|
challengeEvent = challengeEvent,
|
||||||
challengerPubkey = challengerPubkey,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ class ChessAction {
|
|||||||
* @param moveNumber Move number (1-based)
|
* @param moveNumber Move number (1-based)
|
||||||
* @param san Move in Standard Algebraic Notation
|
* @param san Move in Standard Algebraic Notation
|
||||||
* @param fen Resulting position in FEN notation
|
* @param fen Resulting position in FEN notation
|
||||||
* @param opponentPubkey Opponent's pubkey
|
* @param opponent Opponent's pubkey
|
||||||
* @param comment Optional move comment
|
* @param comment Optional move comment
|
||||||
* @param signer Nostr signer
|
* @param signer Nostr signer
|
||||||
*/
|
*/
|
||||||
@@ -97,7 +97,7 @@ class ChessAction {
|
|||||||
moveNumber: Int,
|
moveNumber: Int,
|
||||||
san: String,
|
san: String,
|
||||||
fen: String,
|
fen: String,
|
||||||
opponentPubkey: String,
|
opponent: OpponentTag,
|
||||||
comment: String = "",
|
comment: String = "",
|
||||||
signer: NostrSigner,
|
signer: NostrSigner,
|
||||||
): LiveChessMoveEvent =
|
): LiveChessMoveEvent =
|
||||||
@@ -107,7 +107,7 @@ class ChessAction {
|
|||||||
moveNumber = moveNumber,
|
moveNumber = moveNumber,
|
||||||
san = san,
|
san = san,
|
||||||
fen = fen,
|
fen = fen,
|
||||||
opponentPubkey = opponentPubkey,
|
opponent = opponent,
|
||||||
comment = comment,
|
comment = comment,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@@ -119,7 +119,7 @@ class ChessAction {
|
|||||||
* @param result Game result (1-0, 0-1, or 1/2-1/2)
|
* @param result Game result (1-0, 0-1, or 1/2-1/2)
|
||||||
* @param termination How the game ended
|
* @param termination How the game ended
|
||||||
* @param winnerPubkey Pubkey of winner (if applicable)
|
* @param winnerPubkey Pubkey of winner (if applicable)
|
||||||
* @param opponentPubkey Opponent's pubkey
|
* @param opponent Opponent's pubkey
|
||||||
* @param pgn Optional PGN of complete game
|
* @param pgn Optional PGN of complete game
|
||||||
* @param signer Nostr signer
|
* @param signer Nostr signer
|
||||||
*/
|
*/
|
||||||
@@ -128,7 +128,7 @@ class ChessAction {
|
|||||||
result: GameResult,
|
result: GameResult,
|
||||||
termination: GameTermination,
|
termination: GameTermination,
|
||||||
winnerPubkey: String? = null,
|
winnerPubkey: String? = null,
|
||||||
opponentPubkey: String,
|
opponent: OpponentTag,
|
||||||
pgn: String = "",
|
pgn: String = "",
|
||||||
signer: NostrSigner,
|
signer: NostrSigner,
|
||||||
): LiveChessGameEndEvent =
|
): LiveChessGameEndEvent =
|
||||||
@@ -138,7 +138,7 @@ class ChessAction {
|
|||||||
result = result,
|
result = result,
|
||||||
termination = termination,
|
termination = termination,
|
||||||
winnerPubkey = winnerPubkey,
|
winnerPubkey = winnerPubkey,
|
||||||
opponentPubkey = opponentPubkey,
|
opponent = opponent,
|
||||||
pgn = pgn,
|
pgn = pgn,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
+9
-9
@@ -21,11 +21,14 @@
|
|||||||
package com.vitorpamplona.quartz.nip64Chess.accept
|
package com.vitorpamplona.quartz.nip64Chess.accept
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.BaseChessEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.challenge.LiveChessGameChallengeEvent
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,25 +49,22 @@ class LiveChessGameAcceptEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : BaseChessEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
fun challengeEventId() = tags.challengeEventId()
|
fun challengeEventId() = tags.challengeEventId()
|
||||||
|
|
||||||
fun challengerPubkey(): String? = tags.firstOrNull { it.size >= 2 && it[0] == "p" }?.get(1)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KIND = 30065
|
const val KIND = 30065
|
||||||
const val ALT_DESCRIPTION = "Chess game acceptance"
|
const val ALT_DESCRIPTION = "Chess game acceptance"
|
||||||
|
|
||||||
fun build(
|
fun build(
|
||||||
gameId: String,
|
gameId: String,
|
||||||
challengeEventId: String,
|
challengeEvent: EventHintBundle<LiveChessGameChallengeEvent>,
|
||||||
challengerPubkey: String,
|
|
||||||
createdAt: Long = TimeUtils.now(),
|
createdAt: Long = TimeUtils.now(),
|
||||||
initializer: TagArrayBuilder<LiveChessGameAcceptEvent>.() -> Unit = {},
|
initializer: TagArrayBuilder<LiveChessGameAcceptEvent>.() -> Unit = {},
|
||||||
) = eventTemplate(KIND, "", createdAt) {
|
) = eventTemplate(KIND, "", createdAt) {
|
||||||
add(arrayOf("d", gameId))
|
dTag(gameId)
|
||||||
challengeEvent(challengeEventId)
|
challenge(challengeEvent)
|
||||||
add(arrayOf("p", challengerPubkey))
|
challenger(challengeEvent)
|
||||||
alt(ALT_DESCRIPTION)
|
alt(ALT_DESCRIPTION)
|
||||||
initializer()
|
initializer()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -21,6 +21,11 @@
|
|||||||
package com.vitorpamplona.quartz.nip64Chess.accept
|
package com.vitorpamplona.quartz.nip64Chess.accept
|
||||||
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||||
import com.vitorpamplona.quartz.nip64Chess.accept.tags.ChallengeEventTag
|
import com.vitorpamplona.quartz.nip64Chess.accept.tags.ChallengeEventTag
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.accept.tags.toOpponentTag
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.challenge.LiveChessGameChallengeEvent
|
||||||
|
|
||||||
fun TagArrayBuilder<LiveChessGameAcceptEvent>.challengeEvent(challengeEventId: String) = add(ChallengeEventTag.assemble(challengeEventId))
|
fun TagArrayBuilder<LiveChessGameAcceptEvent>.challenge(challengeHint: EventHintBundle<LiveChessGameChallengeEvent>) = addUnique(ChallengeEventTag.assemble(challengeHint))
|
||||||
|
|
||||||
|
fun TagArrayBuilder<LiveChessGameAcceptEvent>.challenger(challengeHint: EventHintBundle<LiveChessGameChallengeEvent>) = add(challengeHint.toOpponentTag().toTagArray())
|
||||||
|
|||||||
+71
-5
@@ -20,21 +20,87 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.quartz.nip64Chess.accept.tags
|
package com.vitorpamplona.quartz.nip64Chess.accept.tags
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.has
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.EventHintBundle
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.EventIdHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.events.GenericETag
|
||||||
|
import com.vitorpamplona.quartz.nip19Bech32.entities.NEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.challenge.LiveChessGameChallengeEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||||
import com.vitorpamplona.quartz.utils.ensure
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
class ChallengeEventTag {
|
data class ChallengeEventTag(
|
||||||
|
override val eventId: HexKey,
|
||||||
|
) : GenericETag {
|
||||||
|
override var relay: NormalizedRelayUrl? = null
|
||||||
|
override var author: HexKey? = null
|
||||||
|
|
||||||
|
constructor(eventId: HexKey, relayHint: NormalizedRelayUrl? = null, authorPubKeyHex: HexKey? = null) : this(eventId) {
|
||||||
|
this.relay = relayHint
|
||||||
|
this.author = authorPubKeyHex
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toNEvent(): String = NEvent.create(eventId, author, null, relay)
|
||||||
|
|
||||||
|
override fun toTagArray() = assemble(eventId, relay, author)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG_NAME = "e"
|
const val TAG_NAME = "e"
|
||||||
|
|
||||||
fun isTag(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].length == 64
|
fun isTagged(tag: Array<String>) = tag.has(1) && tag[0] == TAG_NAME && tag[1].length == 64
|
||||||
|
|
||||||
fun parse(tag: Array<String>): String? {
|
fun isTagged(
|
||||||
ensure(tag.has(1) && tag[0] == TAG_NAME) { return null }
|
tag: Array<String>,
|
||||||
|
eventId: HexKey,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] == eventId
|
||||||
|
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
eventIds: Set<HexKey>,
|
||||||
|
) = tag.has(1) && tag[0] == TAG_NAME && tag[1] in eventIds
|
||||||
|
|
||||||
|
fun parse(tag: Array<String>): ChallengeEventTag? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].length == 64) { return null }
|
||||||
|
|
||||||
|
val hint = tag.getOrNull(2)?.let { RelayUrlNormalizer.normalizeOrNull(it) }
|
||||||
|
|
||||||
|
return ChallengeEventTag(tag[1], hint, tag.getOrNull(3))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseId(tag: Array<String>): String? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
ensure(tag[1].length == 64) { return null }
|
ensure(tag[1].length == 64) { return null }
|
||||||
return tag[1]
|
return tag[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun assemble(challengeEventId: String) = arrayOf(TAG_NAME, challengeEventId)
|
fun parseAsHint(tag: Array<String>): EventIdHint? {
|
||||||
|
ensure(tag.has(2)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].length == 64) { return null }
|
||||||
|
ensure(tag[2].isNotEmpty()) { return null }
|
||||||
|
|
||||||
|
val hint = RelayUrlNormalizer.normalizeOrNull(tag[2])
|
||||||
|
|
||||||
|
ensure(hint != null) { return null }
|
||||||
|
|
||||||
|
return EventIdHint(tag[1], hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assemble(
|
||||||
|
eventId: HexKey,
|
||||||
|
relay: NormalizedRelayUrl?,
|
||||||
|
author: HexKey?,
|
||||||
|
) = arrayOfNotNull(TAG_NAME, eventId, relay?.url, author)
|
||||||
|
|
||||||
|
fun assemble(eventHint: EventHintBundle<LiveChessGameChallengeEvent>) = assemble(eventHint.event.id, eventHint.relay, eventHint.event.pubKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun EventHintBundle<LiveChessGameChallengeEvent>.toOpponentTag() = OpponentTag(event.pubKey, authorHomeRelay)
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip64Chess.baseEvent
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
|
||||||
|
open class BaseChessEvent(
|
||||||
|
id: HexKey,
|
||||||
|
pubKey: HexKey,
|
||||||
|
createdAt: Long,
|
||||||
|
kind: Int,
|
||||||
|
tags: Array<Array<String>>,
|
||||||
|
content: String,
|
||||||
|
sig: HexKey,
|
||||||
|
) : BaseAddressableEvent(id, pubKey, createdAt, kind, tags, content, sig) {
|
||||||
|
fun opponent() = tags.opponent()
|
||||||
|
|
||||||
|
fun opponentPubkey() = tags.opponentKey()
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip64Chess.baseEvent
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
|
|
||||||
|
fun <T : BaseChessEvent> TagArrayBuilder<T>.opponent(player: OpponentTag) = addUnique(player.toTagArray())
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip64Chess.baseEvent
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.TagArray
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
|
|
||||||
|
fun TagArray.opponent() = firstNotNullOfOrNull(OpponentTag::parse)
|
||||||
|
|
||||||
|
fun TagArray.opponentKey() = firstNotNullOfOrNull(OpponentTag::parseKey)
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip64Chess.baseEvent.tags
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Tag
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.has
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.hints.types.PubKeyHint
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.people.PubKeyReferenceTag
|
||||||
|
import com.vitorpamplona.quartz.utils.arrayOfNotNull
|
||||||
|
import com.vitorpamplona.quartz.utils.ensure
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class OpponentTag(
|
||||||
|
override val pubKey: HexKey,
|
||||||
|
override val relayHint: NormalizedRelayUrl? = null,
|
||||||
|
) : PubKeyReferenceTag {
|
||||||
|
fun toTagArray() = assemble(pubKey, relayHint)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG_NAME = "p"
|
||||||
|
|
||||||
|
fun isTagged(
|
||||||
|
tag: Array<String>,
|
||||||
|
key: HexKey,
|
||||||
|
): Boolean = tag.has(1) && tag[0] == TAG_NAME && tag[1] == key
|
||||||
|
|
||||||
|
fun parse(tag: Tag): OpponentTag? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].length == 64) { return null }
|
||||||
|
|
||||||
|
val hint = tag.getOrNull(2)?.let { RelayUrlNormalizer.Companion.normalizeOrNull(it) }
|
||||||
|
|
||||||
|
return OpponentTag(tag[1], hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseKey(tag: Array<String>): HexKey? {
|
||||||
|
ensure(tag.has(1)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].length == 64) { return null }
|
||||||
|
return tag[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseAsHint(tag: Array<String>): PubKeyHint? {
|
||||||
|
ensure(tag.has(2)) { return null }
|
||||||
|
ensure(tag[0] == TAG_NAME) { return null }
|
||||||
|
ensure(tag[1].length == 64) { return null }
|
||||||
|
ensure(tag[2].isNotEmpty()) { return null }
|
||||||
|
|
||||||
|
val hint = RelayUrlNormalizer.Companion.normalizeOrNull(tag[2])
|
||||||
|
|
||||||
|
ensure(hint != null) { return null }
|
||||||
|
|
||||||
|
return PubKeyHint(tag[1], hint)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assemble(
|
||||||
|
pubkey: HexKey,
|
||||||
|
relayHint: NormalizedRelayUrl?,
|
||||||
|
) = arrayOfNotNull(TAG_NAME, pubkey, relayHint?.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-7
@@ -21,13 +21,17 @@
|
|||||||
package com.vitorpamplona.quartz.nip64Chess.challenge
|
package com.vitorpamplona.quartz.nip64Chess.challenge
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
import com.vitorpamplona.quartz.nip64Chess.Color
|
import com.vitorpamplona.quartz.nip64Chess.Color
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.BaseChessEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.opponent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
import kotlin.let
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Live Chess Game Challenge Event (Kind 30064)
|
* Live Chess Game Challenge Event (Kind 30064)
|
||||||
@@ -49,13 +53,13 @@ class LiveChessGameChallengeEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : BaseChessEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
|
fun gameId() = tags.dTag()
|
||||||
|
|
||||||
fun playerColor() = tags.playerColor()
|
fun playerColor() = tags.playerColor()
|
||||||
|
|
||||||
fun timeControl() = tags.timeControl()
|
fun timeControl() = tags.timeControl()
|
||||||
|
|
||||||
fun opponentPubkey(): String? = tags.firstOrNull { it.size >= 2 && it[0] == "p" }?.get(1)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KIND = 30064
|
const val KIND = 30064
|
||||||
const val ALT_DESCRIPTION = "Chess game challenge"
|
const val ALT_DESCRIPTION = "Chess game challenge"
|
||||||
@@ -63,14 +67,14 @@ class LiveChessGameChallengeEvent(
|
|||||||
fun build(
|
fun build(
|
||||||
gameId: String,
|
gameId: String,
|
||||||
playerColor: Color,
|
playerColor: Color,
|
||||||
opponentPubkey: String? = null,
|
opponent: OpponentTag? = null,
|
||||||
timeControl: String? = null,
|
timeControl: String? = null,
|
||||||
createdAt: Long = TimeUtils.now(),
|
createdAt: Long = TimeUtils.now(),
|
||||||
initializer: TagArrayBuilder<LiveChessGameChallengeEvent>.() -> Unit = {},
|
initializer: TagArrayBuilder<LiveChessGameChallengeEvent>.() -> Unit = {},
|
||||||
) = eventTemplate(KIND, "", createdAt) {
|
) = eventTemplate(KIND, "", createdAt) {
|
||||||
add(arrayOf("d", gameId))
|
dTag(gameId)
|
||||||
playerColor(playerColor)
|
playerColor(playerColor)
|
||||||
opponentPubkey?.let { add(arrayOf("p", it)) }
|
opponent?.let { opponent(opponent) }
|
||||||
timeControl?.let { timeControl(it) }
|
timeControl?.let { timeControl(it) }
|
||||||
alt(ALT_DESCRIPTION)
|
alt(ALT_DESCRIPTION)
|
||||||
initializer()
|
initializer()
|
||||||
|
|||||||
+8
-7
@@ -21,11 +21,14 @@
|
|||||||
package com.vitorpamplona.quartz.nip64Chess.draw
|
package com.vitorpamplona.quartz.nip64Chess.draw
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.BaseChessEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.opponent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,9 +51,7 @@ class LiveChessDrawOfferEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : BaseChessEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
fun opponentPubkey(): String? = tags.firstOrNull { it.size >= 2 && it[0] == "p" }?.get(1)
|
|
||||||
|
|
||||||
fun message(): String = content
|
fun message(): String = content
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -59,13 +60,13 @@ class LiveChessDrawOfferEvent(
|
|||||||
|
|
||||||
fun build(
|
fun build(
|
||||||
gameId: String,
|
gameId: String,
|
||||||
opponentPubkey: String,
|
opponent: OpponentTag,
|
||||||
message: String = "",
|
message: String = "",
|
||||||
createdAt: Long = TimeUtils.now(),
|
createdAt: Long = TimeUtils.now(),
|
||||||
initializer: TagArrayBuilder<LiveChessDrawOfferEvent>.() -> Unit = {},
|
initializer: TagArrayBuilder<LiveChessDrawOfferEvent>.() -> Unit = {},
|
||||||
) = eventTemplate(KIND, message, createdAt) {
|
) = eventTemplate(KIND, message, createdAt) {
|
||||||
add(arrayOf("d", gameId))
|
dTag(gameId)
|
||||||
add(arrayOf("p", opponentPubkey))
|
opponent(opponent)
|
||||||
alt(ALT_DESCRIPTION)
|
alt(ALT_DESCRIPTION)
|
||||||
initializer()
|
initializer()
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -21,13 +21,16 @@
|
|||||||
package com.vitorpamplona.quartz.nip64Chess.end
|
package com.vitorpamplona.quartz.nip64Chess.end
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
import com.vitorpamplona.quartz.nip64Chess.GameResult
|
import com.vitorpamplona.quartz.nip64Chess.GameResult
|
||||||
import com.vitorpamplona.quartz.nip64Chess.GameTermination
|
import com.vitorpamplona.quartz.nip64Chess.GameTermination
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.BaseChessEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.opponent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,15 +55,13 @@ class LiveChessGameEndEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : BaseChessEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
fun result() = tags.result()
|
fun result() = tags.result()
|
||||||
|
|
||||||
fun termination() = tags.termination()
|
fun termination() = tags.termination()
|
||||||
|
|
||||||
fun winnerPubkey() = tags.winnerPubkey()
|
fun winnerPubkey() = tags.winnerPubkey()
|
||||||
|
|
||||||
fun opponentPubkey(): String? = tags.firstOrNull { it.size >= 2 && it[0] == "p" }?.get(1)
|
|
||||||
|
|
||||||
fun pgn(): String = content
|
fun pgn(): String = content
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -72,16 +73,16 @@ class LiveChessGameEndEvent(
|
|||||||
result: GameResult,
|
result: GameResult,
|
||||||
termination: GameTermination,
|
termination: GameTermination,
|
||||||
winnerPubkey: String? = null,
|
winnerPubkey: String? = null,
|
||||||
opponentPubkey: String,
|
opponent: OpponentTag,
|
||||||
pgn: String = "",
|
pgn: String = "",
|
||||||
createdAt: Long = TimeUtils.now(),
|
createdAt: Long = TimeUtils.now(),
|
||||||
initializer: TagArrayBuilder<LiveChessGameEndEvent>.() -> Unit = {},
|
initializer: TagArrayBuilder<LiveChessGameEndEvent>.() -> Unit = {},
|
||||||
) = eventTemplate(KIND, pgn, createdAt) {
|
) = eventTemplate(KIND, pgn, createdAt) {
|
||||||
add(arrayOf("d", gameId))
|
dTag(gameId)
|
||||||
result(result)
|
result(result)
|
||||||
termination(termination)
|
termination(termination)
|
||||||
winnerPubkey?.let { winner(it) }
|
winnerPubkey?.let { winner(it) }
|
||||||
add(arrayOf("p", opponentPubkey))
|
opponent(opponent)
|
||||||
alt("$ALT_DESCRIPTION: ${result.notation}")
|
alt("$ALT_DESCRIPTION: ${result.notation}")
|
||||||
initializer()
|
initializer()
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -21,12 +21,16 @@
|
|||||||
package com.vitorpamplona.quartz.nip64Chess.move
|
package com.vitorpamplona.quartz.nip64Chess.move
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent
|
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||||
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder
|
||||||
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag
|
||||||
import com.vitorpamplona.quartz.nip31Alts.alt
|
import com.vitorpamplona.quartz.nip31Alts.alt
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.BaseChessEvent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.opponent
|
||||||
|
import com.vitorpamplona.quartz.nip64Chess.baseEvent.tags.OpponentTag
|
||||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||||
|
import kotlinx.serialization.json.JsonNull.content
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Live Chess Move Event (Kind 30066)
|
* Live Chess Move Event (Kind 30066)
|
||||||
@@ -50,7 +54,7 @@ class LiveChessMoveEvent(
|
|||||||
tags: Array<Array<String>>,
|
tags: Array<Array<String>>,
|
||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : BaseChessEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
fun gameId() = tags.gameId()
|
fun gameId() = tags.gameId()
|
||||||
|
|
||||||
fun moveNumber() = tags.moveNumber()
|
fun moveNumber() = tags.moveNumber()
|
||||||
@@ -59,8 +63,6 @@ class LiveChessMoveEvent(
|
|||||||
|
|
||||||
fun fen() = tags.fen()
|
fun fen() = tags.fen()
|
||||||
|
|
||||||
fun opponentPubkey(): String? = tags.firstOrNull { it.size >= 2 && it[0] == "p" }?.get(1)
|
|
||||||
|
|
||||||
fun comment(): String = content
|
fun comment(): String = content
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -72,17 +74,17 @@ class LiveChessMoveEvent(
|
|||||||
moveNumber: Int,
|
moveNumber: Int,
|
||||||
san: String,
|
san: String,
|
||||||
fen: String,
|
fen: String,
|
||||||
opponentPubkey: String,
|
opponent: OpponentTag,
|
||||||
comment: String = "",
|
comment: String = "",
|
||||||
createdAt: Long = TimeUtils.now(),
|
createdAt: Long = TimeUtils.now(),
|
||||||
initializer: TagArrayBuilder<LiveChessMoveEvent>.() -> Unit = {},
|
initializer: TagArrayBuilder<LiveChessMoveEvent>.() -> Unit = {},
|
||||||
) = eventTemplate(KIND, comment, createdAt) {
|
) = eventTemplate(KIND, comment, createdAt) {
|
||||||
add(arrayOf("d", "$gameId-$moveNumber"))
|
dTag("$gameId-$moveNumber")
|
||||||
gameId(gameId)
|
gameId(gameId)
|
||||||
moveNumber(moveNumber)
|
moveNumber(moveNumber)
|
||||||
san(san)
|
san(san)
|
||||||
fen(fen)
|
fen(fen)
|
||||||
add(arrayOf("p", opponentPubkey))
|
opponent(opponent)
|
||||||
alt("$ALT_DESCRIPTION: $san")
|
alt("$ALT_DESCRIPTION: $san")
|
||||||
initializer()
|
initializer()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user