Uploads files to new contract
This commit is contained in:
parent
8f689517c7
commit
4bffaf5fb8
4 changed files with 327 additions and 0 deletions
5
TestContract/go.mod
Normal file
5
TestContract/go.mod
Normal file
|
@ -0,0 +1,5 @@
|
|||
module TestContract
|
||||
|
||||
go 1.22
|
||||
|
||||
require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2
|
2
TestContract/go.sum
Normal file
2
TestContract/go.sum
Normal file
|
@ -0,0 +1,2 @@
|
|||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2 h1:4Bfi6A1kPpaTDuwbDVc6x+R4WXgoNN9wIq6XobDlXHs=
|
||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20241223145456-80e18222bca2/go.mod h1:kVLzmbeJJdbIPF2bUYhD8YppIiLXnRQj5yqNZvzbOL0=
|
309
TestContract/main.go
Normal file
309
TestContract/main.go
Normal file
|
@ -0,0 +1,309 @@
|
|||
package TestContract
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||
)
|
||||
|
||||
var notificationName string
|
||||
|
||||
// init initializes notificationName before calling any other smart-contract method
|
||||
func init() {
|
||||
notificationName = "Hello world!"
|
||||
}
|
||||
|
||||
// RuntimeNotify sends runtime notification with "Hello world!" name
|
||||
func RuntimeNotify(args []any) {
|
||||
runtime.Notify(notificationName, args)
|
||||
}
|
||||
|
||||
// RoomStatusWaiting created room wait for join all players
|
||||
// todo описать фазы
|
||||
const (
|
||||
RoomStatusWaiting = "waiting"
|
||||
// RoomStatusGameIsStarted todo мне не нравится это название фазы. оно должно описывать промежуточное состояние
|
||||
//мб RoomStatusGaming
|
||||
// еще до задачи вопроса и после завершения предыдущего раунда
|
||||
RoomStatusGameIsStarted = "game_is_going"
|
||||
RoomStatusRoundIsStarted = "round_is_started"
|
||||
RoomStatusVoting = "voting"
|
||||
RoomStatusFinished = "finished"
|
||||
)
|
||||
|
||||
type Room struct {
|
||||
Id string
|
||||
Host interop.Hash160
|
||||
Status string
|
||||
PrizePool int
|
||||
CountWinners int // ??? //мне кажется норм инт да, они там везде интом оперируют это даже в доке есть
|
||||
Players []Player
|
||||
Rounds []Round
|
||||
}
|
||||
|
||||
type Round struct {
|
||||
number int // Sequence number of round
|
||||
question string
|
||||
answers []Answer
|
||||
}
|
||||
|
||||
type Answer struct {
|
||||
wallet interop.Hash160
|
||||
answer string
|
||||
votes int
|
||||
answerIdx int // Index of sent answer to user - это что, кол-во данных ответов на вопрос?
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
Wallet interop.Hash160 //roundsWon - сколько раундов выиграл - мы тут не храним в итоге?
|
||||
}
|
||||
|
||||
func getRoom(ctx storage.Context, roomId string) *Room {
|
||||
var roomData = storage.Get(ctx, []byte("room:"+roomId))
|
||||
if roomData == nil {
|
||||
panic("Room with roomId=" + roomId + " not found")
|
||||
}
|
||||
|
||||
return roomData.(*Room)
|
||||
}
|
||||
|
||||
func getSender() interop.Hash160 {
|
||||
return runtime.GetScriptContainer().Sender
|
||||
}
|
||||
|
||||
func CreateRoom(host interop.Hash160, countWinners int) string {
|
||||
var ctx = storage.GetContext()
|
||||
var id = uuid.NewString()
|
||||
var room = Room{
|
||||
Id: id,
|
||||
Host: host,
|
||||
Status: RoomStatusWaiting,
|
||||
PrizePool: 0,
|
||||
CountWinners: countWinners,
|
||||
Players: []Player{},
|
||||
Rounds: []Round{},
|
||||
}
|
||||
|
||||
storage.Put(ctx, []byte("room:"+id), room)
|
||||
return id
|
||||
//нужно добавить списание денег
|
||||
}
|
||||
|
||||
func JoinRoom(roomId string, wallet interop.Hash160) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
if room.Status != RoomStatusWaiting {
|
||||
return false //Player cannot join started room
|
||||
}
|
||||
|
||||
for _, player := range room.Players {
|
||||
if player.Wallet.Equals(wallet) {
|
||||
return false // Player already joined room
|
||||
}
|
||||
}
|
||||
|
||||
var player = Player{Wallet: wallet}
|
||||
room.Players = append(room.Players, player)
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
//нужно добавить списание денег
|
||||
}
|
||||
|
||||
func StartGame(roomId string, wallet interop.Hash160) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can start game, room status must be is waiting and players count must be > count winners
|
||||
if room.Host.Equals(wallet) || room.Status != RoomStatusWaiting || len(room.Players) <= room.CountWinners {
|
||||
return false //тут же вроде наоборот не equals
|
||||
}
|
||||
|
||||
room.Status = RoomStatusGameIsStarted
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
}
|
||||
|
||||
func AskQuestion(roomId string, wallet interop.Hash160, question string) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can ask question, room status must be game is started
|
||||
if room.Host.Equals(wallet) || room.Status != RoomStatusGameIsStarted {
|
||||
return false //тут же вроде наоборот не equals
|
||||
}
|
||||
|
||||
newRound := Round{
|
||||
number: len(room.Rounds) + 1,
|
||||
question: question,
|
||||
answers: []Answer{},
|
||||
}
|
||||
room.Rounds = append(room.Rounds, newRound)
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
}
|
||||
|
||||
// todo отсюда я начал писать
|
||||
|
||||
func StartQuestion(roomId string) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can start question, room status must be game is started
|
||||
if !room.Host.Equals(getSender()) || room.Status != RoomStatusGameIsStarted {
|
||||
return false
|
||||
}
|
||||
|
||||
room.Status = RoomStatusRoundIsStarted
|
||||
|
||||
for _, player := range room.Players {
|
||||
var question = room.Rounds[len(room.Rounds)-1].question
|
||||
sendMessageToPlayer(question, player)
|
||||
}
|
||||
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
} //тут еще про nns надо не забыть
|
||||
|
||||
func SendAnswer(roomId string, answer string) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only player can send answer, room status must be round is started
|
||||
if roomContains(room.Players, getSender()) || room.Status != RoomStatusRoundIsStarted {
|
||||
return false
|
||||
}
|
||||
|
||||
newAnswer := Answer{
|
||||
getSender(),
|
||||
answer,
|
||||
0,
|
||||
-1,
|
||||
}
|
||||
room.Rounds[len(room.Rounds)-1].answers = append(room.Rounds[len(room.Rounds)-1].answers, newAnswer)
|
||||
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
}
|
||||
|
||||
// todo проверка отправки ответа (от каждого участника если отправлен ответ, то макс один)
|
||||
|
||||
func roomContains(slice []Player, item interop.Hash160) bool {
|
||||
for _, v := range slice {
|
||||
if v.Wallet.Equals(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func EndQuestion(roomId string) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can end question, room status must be round is started
|
||||
if !room.Host.Equals(getSender()) || room.Status != RoomStatusRoundIsStarted {
|
||||
return false
|
||||
}
|
||||
|
||||
room.Status = RoomStatusVoting
|
||||
|
||||
var round = room.Rounds[len(room.Rounds)-1]
|
||||
|
||||
var result string
|
||||
for i, answer := range round.answers {
|
||||
// todo временный комментарий: проставляем индексы ответам как их отправили в вывод, чтобы потом можно было соотнести
|
||||
// интовый голос за ответ с игроком
|
||||
answer.answerIdx = i
|
||||
result += fmt.Sprintf("%d: %s\n", i, answer.answer)
|
||||
}
|
||||
|
||||
for _, player := range room.Players {
|
||||
sendMessageToPlayer(result, player)
|
||||
}
|
||||
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
}
|
||||
|
||||
func ChooseAnswer(roomId string, answerIdx int) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can choose answer, room status must be voting
|
||||
if !room.Host.Equals(getSender()) || room.Status != RoomStatusVoting {
|
||||
return false
|
||||
}
|
||||
|
||||
var round = room.Rounds[len(room.Rounds)-1]
|
||||
|
||||
for _, answer := range round.answers {
|
||||
if answer.answerIdx == answerIdx {
|
||||
answer.votes += 1
|
||||
}
|
||||
}
|
||||
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
}
|
||||
|
||||
func sendMessageToPlayer(message string, player Player) {
|
||||
// todo
|
||||
}
|
||||
|
||||
// todo можно прям сюда подсовывать ссылку на другой контракт кастомный и дефолт реализацию оставить в методе, а кастомную условием
|
||||
// нам сказали, что ссылку на другой контракт нельзя чисто, используем nns
|
||||
func GetWinner(roomId string) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can get winner, room status must be voting
|
||||
if !room.Host.Equals(getSender()) || room.Status != RoomStatusVoting {
|
||||
return false
|
||||
}
|
||||
|
||||
var round = room.Rounds[len(room.Rounds)-1]
|
||||
|
||||
if len(round.answers) == 0 {
|
||||
panic(fmt.Sprintf("Round number %d does not have answers", len(room.Rounds)))
|
||||
}
|
||||
|
||||
winner := round.answers[0]
|
||||
|
||||
// todo для mvp пока топ 1 победитель. потом сделаем CountWinners или кастомные реализации распределений
|
||||
for _, answer := range round.answers {
|
||||
if answer.votes > winner.votes {
|
||||
winner = answer
|
||||
}
|
||||
}
|
||||
|
||||
for _, player := range room.Players {
|
||||
sendMessageToPlayer(winner.answer, player)
|
||||
}
|
||||
|
||||
// todo отправка награды
|
||||
|
||||
room.Status = RoomStatusGameIsStarted // Next game cycle available. to AskQuestion
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
}
|
||||
|
||||
func FinishGame(roomId string) bool {
|
||||
var ctx = storage.GetContext()
|
||||
var room = getRoom(ctx, roomId)
|
||||
|
||||
// Only host can finish game, room status must be game is going
|
||||
if !room.Host.Equals(getSender()) || room.Status != RoomStatusGameIsStarted {
|
||||
return false
|
||||
}
|
||||
|
||||
// todo победитель всей игры? итоги? что нибудь еще?
|
||||
|
||||
room.Status = RoomStatusFinished
|
||||
storage.Put(ctx, []byte("room:"+roomId), room)
|
||||
return true
|
||||
// todo добавить вилку, что если ВСЕ участники согласились закончить игру - заканчиваем
|
||||
}
|
||||
|
||||
// todo логика выкидывания игрока из игры, если пропускает несколько вопросов подряд - делаем булевый флаг по которому определяем, активен игрок или нет
|
11
TestContract/neo-go.yml
Normal file
11
TestContract/neo-go.yml
Normal file
|
@ -0,0 +1,11 @@
|
|||
name: TestContract
|
||||
sourceurl: http://example.com/
|
||||
safemethods: []
|
||||
supportedstandards: []
|
||||
events:
|
||||
- name: Hello world!
|
||||
parameters:
|
||||
- name: args
|
||||
type: Array
|
||||
permissions:
|
||||
- methods: '*'
|
Loading…
Add table
Reference in a new issue