@@ -2,22 +2,23 @@ package commands
2
2
3
3
import (
4
4
"errors"
5
+ "github.com/RobolabGs2/botctl/cli"
6
+ "github.com/RobolabGs2/botctl/executil"
7
+ "github.com/RobolabGs2/botctl/games"
8
+ "gopkg.in/yaml.v3"
5
9
"io/fs"
6
10
"log"
7
11
"os"
8
12
"path"
9
13
"runtime"
10
14
"sync"
11
-
12
- "github.com/RobolabGs2/botctl/cli"
13
- "github.com/RobolabGs2/botctl/executil"
14
- "github.com/RobolabGs2/botctl/games"
15
- "gopkg.in/yaml.v3"
15
+ "time"
16
16
)
17
17
18
18
type Tournament struct {
19
19
Concurrency int `name:"c" default:"0" desc:"Количество одновременных соревнований. '0' - количество виртуальных ядер минус 1"`
20
- BotsList string `name:"config" default:"tournament.yaml" desc:"A ботов для турнира"`
20
+ Config string `name:"config" default:"tournament.yaml" desc:"Список ботов для турнира"`
21
+ config TournamentConfigs
21
22
}
22
23
23
24
func (t * Tournament ) Description () string {
@@ -52,6 +53,11 @@ func (t *Tournament) Run(args []string, streams cli.Streams) error {
52
53
if err != nil {
53
54
return err
54
55
}
56
+ testBots (bots , streams , t .Concurrency )
57
+ return runTournament (bots , botsDesc , streams , t .Concurrency )
58
+ }
59
+
60
+ func runTournament (bots []games.Bot , botsDesc []BotDescription , streams cli.Streams , concurrency int ) error {
55
61
battles := make (chan * games.Battle )
56
62
go func () {
57
63
for i , first := range bots {
@@ -65,15 +71,37 @@ func (t *Tournament) Run(args []string, streams cli.Streams) error {
65
71
66
72
scores := MakeScoreTable (botsDesc )
67
73
output := log .New (streams .Out , "" , 0 )
68
- for battle := range RunRunners (t . Concurrency , battles ) {
74
+ for battle := range RunRunners (concurrency , battles ) {
69
75
err := scores .Update (battle )
70
76
if err != nil {
71
- return err
77
+ output .Printf (
78
+ "Неудачное сражение между %s vs %s: %s" ,
79
+ battle .Players [0 ].Name , battle .Players [1 ].Name , err )
80
+ continue
72
81
}
73
- log .Println (battle .State (),
82
+ output .Println (scores )
83
+ output .Println (battle .State (),
74
84
battle .Players [0 ].Name , battle .GameResult (0 ),
75
85
battle .Players [1 ].Name , battle .GameResult (1 ))
76
- output .Println (scores )
86
+ output .Println ()
87
+ }
88
+ return nil
89
+ }
90
+
91
+ func testBots (bots []games.Bot , streams cli.Streams , concurrency int ) error {
92
+ battles := make (chan * games.Battle )
93
+ go func () {
94
+ for _ , bot := range bots {
95
+ battles <- & games.Battle {Players : [2 ]games.Bot {bot , bot }}
96
+ }
97
+ close (battles )
98
+ }()
99
+
100
+ output := log .New (streams .Out , "" , 0 )
101
+ for battle := range RunRunners (concurrency , battles ) {
102
+ output .Println ("Результат тестирования бота" , battle .Players [0 ].Name )
103
+ _ = analizeTestBattle (output , streams , battle )
104
+ output .Println ()
77
105
}
78
106
return nil
79
107
}
@@ -90,34 +118,47 @@ func MakeBots(botsDesc []BotDescription, dirName string) ([]games.Bot, error) {
90
118
return bots , nil
91
119
}
92
120
121
+ type BotsConfig map [string ]BotDescription
122
+
123
+ func (bots BotsConfig ) Slice () []BotDescription {
124
+ botsDesc := make ([]BotDescription , 0 , len (bots ))
125
+ for author , bot := range bots {
126
+ bot .Author = author
127
+ botsDesc = append (botsDesc , bot )
128
+ }
129
+ return botsDesc
130
+ }
131
+
132
+ type TournamentConfigs struct {
133
+ Bots BotsConfig
134
+ Timeout time.Duration
135
+ Game string
136
+ Rounds int
137
+ }
138
+
93
139
func (t * Tournament ) readBotDescriptions (dir fs.FS ) ([]BotDescription , error ) {
94
- var botsDesc []BotDescription
95
- if executil .CheckFileFs (dir , t .BotsList ) == nil {
96
- config , err := dir .Open (t .BotsList )
140
+ if executil .CheckFileFs (dir , t .Config ) == nil {
141
+ config , err := dir .Open (t .Config )
97
142
if err != nil {
98
143
return nil , err
99
144
}
100
- bots := map [string ]BotDescription {}
101
- if err := yaml .NewDecoder (config ).Decode (bots ); err != nil {
102
- return nil , err
103
- }
104
- for author , bot := range bots {
105
- bot .Author = author
106
- botsDesc = append (botsDesc , bot )
107
- }
108
- } else {
109
- files , err := fs .ReadDir (dir , "." )
110
- if err != nil {
145
+ if err := yaml .NewDecoder (config ).Decode (& t .config ); err != nil {
111
146
return nil , err
112
147
}
113
- for _ , file := range files {
114
- if executil .Executable (file ) {
115
- log .Println ("Detect bot" , file .Name ())
116
- botsDesc = append (botsDesc , BotDescription {
117
- Author : file .Name (),
118
- Cmd : file .Name (),
119
- })
120
- }
148
+ return t .config .Bots .Slice (), nil
149
+ }
150
+ var botsDesc []BotDescription
151
+ files , err := fs .ReadDir (dir , "." )
152
+ if err != nil {
153
+ return nil , err
154
+ }
155
+ for _ , file := range files {
156
+ if executil .Executable (file ) {
157
+ log .Println ("Detect bot" , file .Name ())
158
+ botsDesc = append (botsDesc , BotDescription {
159
+ Author : file .Name (),
160
+ Cmd : file .Name (),
161
+ })
121
162
}
122
163
}
123
164
return botsDesc , nil
@@ -133,7 +174,7 @@ func RunRunners(concurrency int, battles chan *games.Battle) chan *games.Battle
133
174
runnersGroup .Add (concurrency )
134
175
finished := make (chan * games.Battle )
135
176
for i := 0 ; i < concurrency ; i ++ {
136
- go games .Runner ( runnersGroup , battles , finished )
177
+ go games .RunnerWithTimeout ( 2 * time . Minute , runnersGroup , battles , finished )
137
178
}
138
179
go func () {
139
180
runnersGroup .Wait ()
0 commit comments