Go で書き直した Ikemen
Revisão | c24afe66fb38fcbcd13f561f6f55e2a92acbffcf (tree) |
---|---|
Hora | 2016-12-10 00:34:59 |
Autor | SUEHIRO <supersuehiro@user...> |
Commiter | SUEHIRO |
式の処理を書き始める
@@ -5,24 +5,370 @@ import ( | ||
5 | 5 | "strings" |
6 | 6 | ) |
7 | 7 | |
8 | -type StateByteCode struct{} | |
8 | +const kuuhaktokigou = " !=<>()|&+-*/%,[]^|:\"\t\r\n" | |
9 | + | |
10 | +type StateType int32 | |
11 | + | |
12 | +const ( | |
13 | + ST_S StateType = 1 << iota | |
14 | + ST_C | |
15 | + ST_A | |
16 | + ST_L | |
17 | + ST_N | |
18 | + ST_U | |
19 | + ST_D = ST_L | |
20 | + ST_F = ST_N | |
21 | + ST_P = ST_U | |
22 | +) | |
23 | + | |
24 | +type AttackType int32 | |
25 | + | |
26 | +const ( | |
27 | + AT_NA AttackType = 1 << (iota + 6) | |
28 | + AT_NT | |
29 | + AT_NP | |
30 | + AT_SA | |
31 | + AT_ST | |
32 | + AT_SP | |
33 | + AT_HA | |
34 | + AT_HT | |
35 | + AT_HP | |
36 | +) | |
37 | + | |
38 | +type MoveType int32 | |
39 | + | |
40 | +const ( | |
41 | + MT_I MoveType = 1 << (iota + 15) | |
42 | + MT_H | |
43 | + MT_A = MT_I + 1 | |
44 | + MT_U = MT_H + 1 | |
45 | + MT_MNS = MT_I | |
46 | + MT_PLS = MT_H | |
47 | +) | |
48 | + | |
49 | +type ValueType int | |
50 | + | |
51 | +const ( | |
52 | + VT_Any ValueType = iota | |
53 | + VT_Float | |
54 | + VT_Int | |
55 | + VT_Bool | |
56 | +) | |
57 | + | |
58 | +type ByteExp []byte | |
59 | +type StateByteCode struct { | |
60 | + stateType StateType | |
61 | + moveType MoveType | |
62 | + physics StateType | |
63 | +} | |
64 | + | |
65 | +func newStateByteCode() *StateByteCode { | |
66 | + return &StateByteCode{stateType: ST_S, moveType: MT_I, physics: ST_N} | |
67 | +} | |
68 | + | |
9 | 69 | type ByteCode struct{ states map[int32]StateByteCode } |
10 | 70 | |
11 | 71 | func newByteCode() *ByteCode { |
12 | 72 | return &ByteCode{states: make(map[int32]StateByteCode)} |
13 | 73 | } |
14 | 74 | |
75 | +type ExpFunc func(out *ByteExp, in *string) (ValueType, error) | |
15 | 76 | type Compiler struct{ cmdl *CommandList } |
16 | 77 | |
17 | 78 | func newCompiler() *Compiler { |
18 | 79 | return &Compiler{} |
19 | 80 | } |
81 | +func (c *Compiler) tokenizer(in *string) string { | |
82 | + *in = strings.TrimSpace(*in) | |
83 | + if len(*in) == 0 { | |
84 | + return "" | |
85 | + } | |
86 | + switch (*in)[0] { | |
87 | + case '=': | |
88 | + *in = (*in)[1:] | |
89 | + return "=" | |
90 | + case ':': | |
91 | + if len(*in) >= 2 && (*in)[1] == '=' { | |
92 | + *in = (*in)[2:] | |
93 | + return ":=" | |
94 | + } | |
95 | + *in = (*in)[1:] | |
96 | + return ":" | |
97 | + case '!': | |
98 | + if len(*in) >= 2 && (*in)[1] == '=' { | |
99 | + *in = (*in)[2:] | |
100 | + return "!=" | |
101 | + } | |
102 | + *in = (*in)[1:] | |
103 | + return "!" | |
104 | + case '>': | |
105 | + if len(*in) >= 2 && (*in)[1] == '=' { | |
106 | + *in = (*in)[2:] | |
107 | + return ">=" | |
108 | + } | |
109 | + *in = (*in)[1:] | |
110 | + return ">" | |
111 | + case '<': | |
112 | + if len(*in) >= 2 && (*in)[1] == '=' { | |
113 | + *in = (*in)[2:] | |
114 | + return "<=" | |
115 | + } | |
116 | + *in = (*in)[1:] | |
117 | + return "<" | |
118 | + case '~': | |
119 | + *in = (*in)[1:] | |
120 | + return "~" | |
121 | + case '&': | |
122 | + if len(*in) >= 2 && (*in)[1] == '&' { | |
123 | + *in = (*in)[2:] | |
124 | + return "&&" | |
125 | + } | |
126 | + *in = (*in)[1:] | |
127 | + return "&" | |
128 | + case '^': | |
129 | + if len(*in) >= 2 && (*in)[1] == '^' { | |
130 | + *in = (*in)[2:] | |
131 | + return "^^" | |
132 | + } | |
133 | + *in = (*in)[1:] | |
134 | + return "^" | |
135 | + case '|': | |
136 | + if len(*in) >= 2 && (*in)[1] == '|' { | |
137 | + *in = (*in)[2:] | |
138 | + return "||" | |
139 | + } | |
140 | + *in = (*in)[1:] | |
141 | + return "|" | |
142 | + case '+': | |
143 | + *in = (*in)[1:] | |
144 | + return "+" | |
145 | + case '-': | |
146 | + *in = (*in)[1:] | |
147 | + return "-" | |
148 | + case '*': | |
149 | + if len(*in) >= 2 && (*in)[1] == '*' { | |
150 | + *in = (*in)[2:] | |
151 | + return "**" | |
152 | + } | |
153 | + *in = (*in)[1:] | |
154 | + return "*" | |
155 | + case '/': | |
156 | + *in = (*in)[1:] | |
157 | + return "/" | |
158 | + case '%': | |
159 | + *in = (*in)[1:] | |
160 | + return "%" | |
161 | + case ',': | |
162 | + *in = (*in)[1:] | |
163 | + return "," | |
164 | + case '(': | |
165 | + *in = (*in)[1:] | |
166 | + return "(" | |
167 | + case ')': | |
168 | + *in = (*in)[1:] | |
169 | + return ")" | |
170 | + case '[': | |
171 | + *in = (*in)[1:] | |
172 | + return "[" | |
173 | + case ']': | |
174 | + *in = (*in)[1:] | |
175 | + return "]" | |
176 | + case '"': | |
177 | + *in = (*in)[1:] | |
178 | + return "\"" | |
179 | + } | |
180 | + ia := strings.IndexAny(*in, kuuhaktokigou) | |
181 | + if ia < 0 { | |
182 | + ia = len(*in) | |
183 | + } | |
184 | + token := (*in)[:ia] | |
185 | + *in = (*in)[ia:] | |
186 | + return token | |
187 | +} | |
188 | +func (c *Compiler) expBoolOr(out *ByteExp, in *string) (ValueType, error) { | |
189 | + unimplemented() | |
190 | + return 0, nil | |
191 | +} | |
192 | +func (c *Compiler) typedExp(ef ExpFunc, out *ByteExp, in *string, | |
193 | + vt ValueType) error { | |
194 | + t, err := ef(out, in) | |
195 | + if err != nil { | |
196 | + return err | |
197 | + } | |
198 | + unimplemented() | |
199 | + return nil | |
200 | +} | |
201 | +func (c *Compiler) fullExpression(out *ByteExp, in *string, | |
202 | + vt ValueType) error { | |
203 | + if err := c.typedExp(c.expBoolOr, out, in, vt); err != nil { | |
204 | + return err | |
205 | + } | |
206 | + if token := c.tokenizer(in); len(token) > 0 { | |
207 | + return Error(token + "が不正です") | |
208 | + } | |
209 | + return nil | |
210 | +} | |
20 | 211 | func (c *Compiler) parseSection(lines []string, i *int, |
21 | - f func(name, data string) error) (IniSection, error) { | |
212 | + sctrl func(name, data string) error) (IniSection, error) { | |
22 | 213 | is := NewIniSection() |
23 | - unimplemented() | |
214 | + for ; *i < len(lines); (*i)++ { | |
215 | + line := strings.ToLower(strings.TrimSpace( | |
216 | + strings.SplitN(lines[*i], ";", 2)[0])) | |
217 | + if len(line) > 0 && line[0] == '[' { | |
218 | + (*i)-- | |
219 | + break | |
220 | + } | |
221 | + var name, data string | |
222 | + if len(line) >= 3 && strings.ToLower(line[:3]) == "var" { | |
223 | + name, data = "var", line | |
224 | + } else if len(line) >= 4 && strings.ToLower(line[:4]) == "fvar" { | |
225 | + name, data = "fvar", line | |
226 | + } else if len(line) >= 6 && strings.ToLower(line[:6]) == "sysvar" { | |
227 | + name, data = "sysvar", line | |
228 | + } else if len(line) >= 7 && strings.ToLower(line[:7]) == "sysfvar" { | |
229 | + name, data = "sysfvar", line | |
230 | + } else { | |
231 | + ia := strings.IndexAny(line, "= \t") | |
232 | + if ia > 0 { | |
233 | + name = strings.ToLower(line[:ia]) | |
234 | + ia = strings.Index(line, "=") | |
235 | + if ia >= 0 { | |
236 | + data = strings.TrimSpace(line[ia+1:]) | |
237 | + } | |
238 | + } | |
239 | + } | |
240 | + if len(name) > 0 { | |
241 | + _, ok := is[name] | |
242 | + if ok && (len(name) < 7 || name[:7] != "trigger") { | |
243 | + if sys.ignoreMostErrors { | |
244 | + continue | |
245 | + } | |
246 | + return nil, Error(name + "が重複しています") | |
247 | + } | |
248 | + if sctrl != nil { | |
249 | + switch name { | |
250 | + case "type", "persistent", "ignorehitpause": | |
251 | + default: | |
252 | + if len(name) < 7 || name[:7] != "trigger" { | |
253 | + is[name] = data | |
254 | + continue | |
255 | + } | |
256 | + } | |
257 | + if err := sctrl(name, data); err != nil { | |
258 | + return nil, err | |
259 | + } | |
260 | + } else { | |
261 | + is[name] = data | |
262 | + } | |
263 | + } | |
264 | + } | |
24 | 265 | return is, nil |
25 | 266 | } |
267 | +func (c *Compiler) stateSec(is IniSection, f func() error) error { | |
268 | + if err := f(); err != nil { | |
269 | + return err | |
270 | + } | |
271 | + if !sys.ignoreMostErrors { | |
272 | + var str string | |
273 | + for k, _ := range is { | |
274 | + if len(str) > 0 { | |
275 | + str += ", " | |
276 | + } | |
277 | + str += k | |
278 | + } | |
279 | + if len(str) > 0 { | |
280 | + return Error(str + "は無効なキー名です") | |
281 | + } | |
282 | + } | |
283 | + return nil | |
284 | +} | |
285 | +func (c *Compiler) stateParam(is IniSection, name string, | |
286 | + f func(string) error) error { | |
287 | + data, ok := is[name] | |
288 | + if ok { | |
289 | + if err := f(data); err != nil { | |
290 | + return Error(name + ": " + err.Error()) | |
291 | + } | |
292 | + delete(is, name) | |
293 | + } | |
294 | + return nil | |
295 | +} | |
296 | +func (c *Compiler) stateDef(is IniSection, sbc *StateByteCode) error { | |
297 | + return c.stateSec(is, func() error { | |
298 | + if err := c.stateParam(is, "type", func(data string) error { | |
299 | + if len(data) == 0 { | |
300 | + return Error("値が指定されていません") | |
301 | + } | |
302 | + switch strings.ToLower(data)[0] { | |
303 | + case 's': | |
304 | + sbc.stateType = ST_S | |
305 | + case 'c': | |
306 | + sbc.stateType = ST_C | |
307 | + case 'a': | |
308 | + sbc.stateType = ST_A | |
309 | + case 'l': | |
310 | + sbc.stateType = ST_L | |
311 | + case 'u': | |
312 | + sbc.stateType = ST_U | |
313 | + default: | |
314 | + return Error(data + "が無効な値です") | |
315 | + } | |
316 | + return nil | |
317 | + }); err != nil { | |
318 | + return err | |
319 | + } | |
320 | + if err := c.stateParam(is, "movetype", func(data string) error { | |
321 | + if len(data) == 0 { | |
322 | + return Error("値が指定されていません") | |
323 | + } | |
324 | + switch strings.ToLower(data)[0] { | |
325 | + case 'i': | |
326 | + sbc.moveType = MT_I | |
327 | + case 'a': | |
328 | + sbc.moveType = MT_A | |
329 | + case 'h': | |
330 | + sbc.moveType = MT_H | |
331 | + case 'u': | |
332 | + sbc.moveType = MT_U | |
333 | + default: | |
334 | + return Error(data + "が無効な値です") | |
335 | + } | |
336 | + return nil | |
337 | + }); err != nil { | |
338 | + return err | |
339 | + } | |
340 | + if err := c.stateParam(is, "physics", func(data string) error { | |
341 | + if len(data) == 0 { | |
342 | + return Error("値が指定されていません") | |
343 | + } | |
344 | + switch strings.ToLower(data)[0] { | |
345 | + case 's': | |
346 | + sbc.physics = ST_S | |
347 | + case 'c': | |
348 | + sbc.physics = ST_C | |
349 | + case 'a': | |
350 | + sbc.physics = ST_A | |
351 | + case 'n': | |
352 | + sbc.physics = ST_N | |
353 | + case 'u': | |
354 | + sbc.physics = ST_U | |
355 | + default: | |
356 | + return Error(data + "が無効な値です") | |
357 | + } | |
358 | + return nil | |
359 | + }); err != nil { | |
360 | + return err | |
361 | + } | |
362 | + if err := c.stateParam(is, "hitcountpersist", func(data string) error { | |
363 | + unimplemented() | |
364 | + return nil | |
365 | + }); err != nil { | |
366 | + return err | |
367 | + } | |
368 | + unimplemented() | |
369 | + return nil | |
370 | + }) | |
371 | +} | |
26 | 372 | func (c *Compiler) stateCompile(bc *ByteCode, filename, def string) error { |
27 | 373 | var lines []string |
28 | 374 | if err := LoadFile(&filename, def, func(filename string) error { |
@@ -41,10 +387,8 @@ func (c *Compiler) stateCompile(bc *ByteCode, filename, def string) error { | ||
41 | 387 | } |
42 | 388 | existInThisFile := make(map[int32]bool) |
43 | 389 | for ; i < len(lines); i++ { |
44 | - line := strings.ToLower(lines[i]) | |
45 | - if idx := strings.Index(line, ";"); idx >= 0 { | |
46 | - line = strings.TrimSpace(line[:idx]) | |
47 | - } | |
390 | + line := strings.ToLower(strings.TrimSpace( | |
391 | + strings.SplitN(lines[i], ";", 2)[0])) | |
48 | 392 | if len(line) < 11 || line[0] != '[' || line[len(line)-1] != ']' || |
49 | 393 | line[1:10] != "statedef " { |
50 | 394 | continue |
@@ -59,6 +403,10 @@ func (c *Compiler) stateCompile(bc *ByteCode, filename, def string) error { | ||
59 | 403 | if err != nil { |
60 | 404 | return errmes(err) |
61 | 405 | } |
406 | + sbc := newStateByteCode() | |
407 | + if err := c.stateDef(is, sbc); err != nil { | |
408 | + return errmes(err) | |
409 | + } | |
62 | 410 | unimplemented() |
63 | 411 | } |
64 | 412 | return nil |
@@ -428,12 +428,21 @@ func (ni *NetInput) Close() { unimplemented() } | ||
428 | 428 | func (ni *NetInput) Input(cb *CommandBuffer, i int, facing int32) { |
429 | 429 | unimplemented() |
430 | 430 | } |
431 | +func (ni *NetInput) Stop() { unimplemented() } | |
432 | +func (ni *NetInput) Synchronize() error { | |
433 | + unimplemented() | |
434 | + return nil | |
435 | +} | |
431 | 436 | |
432 | 437 | type FileInput struct{ ib []InputBits } |
433 | 438 | |
434 | -func (ni *FileInput) Close() { unimplemented() } | |
435 | -func (ni *FileInput) Input(cb *CommandBuffer, i int, facing int32) { | |
439 | +func (fi *FileInput) Close() { unimplemented() } | |
440 | +func (fi *FileInput) Input(cb *CommandBuffer, i int, facing int32) { | |
441 | + unimplemented() | |
442 | +} | |
443 | +func (fi *FileInput) Synchronize() error { | |
436 | 444 | unimplemented() |
445 | + return nil | |
437 | 446 | } |
438 | 447 | |
439 | 448 | type AiInput struct { |
@@ -381,6 +381,10 @@ func systemScriptInit(l *lua.LState) { | ||
381 | 381 | l.Push(lua.LNumber(sys.sel.SetStageNo(int(numArg(l, 1))))) |
382 | 382 | return 1 |
383 | 383 | }) |
384 | + luaRegister(l, "selectStage", func(*lua.LState) int { | |
385 | + sys.sel.SelectStage(int(numArg(l, 1))) | |
386 | + return 0 | |
387 | + }) | |
384 | 388 | luaRegister(l, "setTeamMode", func(*lua.LState) int { |
385 | 389 | tn := int(numArg(l, 1)) |
386 | 390 | if tn < 1 || tn > 2 { |
@@ -433,6 +437,10 @@ func systemScriptInit(l *lua.LState) { | ||
433 | 437 | l.Push(lua.LNumber(ret)) |
434 | 438 | return 1 |
435 | 439 | }) |
440 | + luaRegister(l, "getStageName", func(*lua.LState) int { | |
441 | + l.Push(lua.LString(sys.sel.GetStageName(int(numArg(l, 1))))) | |
442 | + return 1 | |
443 | + }) | |
436 | 444 | luaRegister(l, "refresh", func(*lua.LState) int { |
437 | 445 | sys.await(60) |
438 | 446 | if sys.gameEnd { |
@@ -545,4 +553,64 @@ func systemScriptInit(l *lua.LState) { | ||
545 | 553 | sys.loadStart() |
546 | 554 | return 0 |
547 | 555 | }) |
556 | + luaRegister(l, "game", func(l *lua.LState) int { | |
557 | + if sys.gameEnd { | |
558 | + l.Push(lua.LNumber(-1)) | |
559 | + return 1 | |
560 | + } | |
561 | + winp := int32(0) | |
562 | + sys.rexisted = [2]int32{0, 0} | |
563 | + mw := sys.rexisted | |
564 | + for i := range sys.lifebar.wi { | |
565 | + sys.lifebar.wi[i].clear() | |
566 | + } | |
567 | + sys.draws = 0 | |
568 | + load := func() error { | |
569 | + sys.loader.runTread() | |
570 | + for sys.loader.state != LS_Complete { | |
571 | + if sys.loader.state == LS_Error { | |
572 | + return sys.loader.err | |
573 | + } | |
574 | + sys.await(60) | |
575 | + } | |
576 | + return nil | |
577 | + } | |
578 | + fight := func() (int32, error) { | |
579 | + if err := load(); err != nil { | |
580 | + return -1, err | |
581 | + } | |
582 | + unimplemented() | |
583 | + if sys.round == 1 { | |
584 | + if sys.tmode[1] == TM_Turns { | |
585 | + mw[0] = int32(sys.numTurns[1]) | |
586 | + } else { | |
587 | + mw[0] = sys.lifebar.ro.match_wins | |
588 | + } | |
589 | + if sys.tmode[0] == TM_Turns { | |
590 | + mw[1] = int32(sys.numTurns[0]) | |
591 | + } else { | |
592 | + mw[1] = sys.lifebar.ro.match_wins | |
593 | + } | |
594 | + } | |
595 | + unimplemented() | |
596 | + return winp, nil | |
597 | + } | |
598 | + if sys.netInput != nil { | |
599 | + sys.netInput.Stop() | |
600 | + } | |
601 | + defer sys.synchronize() | |
602 | + for { | |
603 | + var err error | |
604 | + if winp, err = fight(); err != nil { | |
605 | + l.RaiseError(err.Error()) | |
606 | + } | |
607 | + if winp < 0 || sys.tmode[0] != TM_Turns && sys.tmode[1] != TM_Turns || | |
608 | + sys.wins[0] >= mw[0] || sys.wins[1] >= mw[1] || sys.gameEnd { | |
609 | + break | |
610 | + } | |
611 | + unimplemented() | |
612 | + } | |
613 | + l.Push(lua.LNumber(winp)) | |
614 | + return 1 | |
615 | + }) | |
548 | 616 | } |
@@ -83,6 +83,7 @@ type System struct { | ||
83 | 83 | round int32 |
84 | 84 | wins [2]int32 |
85 | 85 | rexisted [2]int32 |
86 | + draws int32 | |
86 | 87 | loader Loader |
87 | 88 | chars [MaxSimul * 2][]*Char |
88 | 89 | cgi [MaxSimul * 2]CharGlobalInfo |
@@ -173,6 +174,14 @@ func (s *System) loadStart() { | ||
173 | 174 | s.loaderReset() |
174 | 175 | s.loader.runTread() |
175 | 176 | } |
177 | +func (s *System) synchronize() error { | |
178 | + if s.fileInput != nil { | |
179 | + return s.fileInput.Synchronize() | |
180 | + } else if s.netInput != nil { | |
181 | + return s.netInput.Synchronize() | |
182 | + } | |
183 | + return nil | |
184 | +} | |
176 | 185 | |
177 | 186 | type SelectChar struct { |
178 | 187 | def, name string |
@@ -224,6 +233,16 @@ func (s *Select) SetStageNo(n int) int { | ||
224 | 233 | return s.curStageNo |
225 | 234 | } |
226 | 235 | func (s *Select) SelectStage(n int) { s.selectedStageNo = n } |
236 | +func (s *Select) GetStageName(n int) string { | |
237 | + n %= len(s.stagelist) + 1 | |
238 | + if n < 0 { | |
239 | + n += len(s.stagelist) + 1 | |
240 | + } | |
241 | + if n == 0 { | |
242 | + return "Random" | |
243 | + } | |
244 | + return s.stagelist[n-1].name | |
245 | +} | |
227 | 246 | func (s *Select) AddCahr(def string) { |
228 | 247 | s.charlist = append(s.charlist, SelectChar{}) |
229 | 248 | sc := &s.charlist[len(s.charlist)-1] |
@@ -297,7 +316,7 @@ func (s *Select) AddStage(def string) error { | ||
297 | 316 | }); err != nil { |
298 | 317 | return err |
299 | 318 | } |
300 | - i, info := 0, false | |
319 | + i, info := 0, true | |
301 | 320 | s.stagelist = append(s.stagelist, SelectStage{}) |
302 | 321 | ss := &s.stagelist[len(s.stagelist)-1] |
303 | 322 | ss.def = def |