9fans.net/go@v0.0.5/games/4s/xs.go (about) 1 // games/4s - a tetris clone 2 // 3 // Derived from Plan 9's /sys/src/games/xs.c 4 // http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c 5 6 /* 7 * engine for 4s, 5s, etc 8 */ 9 10 package main 11 12 import ( 13 "fmt" 14 "image" 15 "log" 16 "math/rand" 17 "os" 18 "time" 19 20 "9fans.net/go/draw" 21 ) 22 23 /* 24 Cursor whitearrow = { 25 {0, 0}, 26 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 27 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 28 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 29 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }, 30 {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, 31 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, 32 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, 33 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, } 34 }; 35 */ 36 37 const ( 38 CNone = 0 39 CBounds = 1 40 CPiece = 2 41 NX = 10 42 NY = 20 43 44 NCOL = 10 45 46 MAXN = 5 47 ) 48 49 var ( 50 N int 51 display *draw.Display 52 screen *draw.Image 53 screenr image.Rectangle 54 55 board [NY][NX]byte 56 rboard image.Rectangle 57 pscore image.Point 58 scoresz image.Point 59 pcsz = 32 60 pos image.Point 61 bb, bbmask, bb2, bb2mask *draw.Image 62 whitemask *draw.Image 63 br, br2 image.Rectangle 64 points int 65 dt int 66 DY int 67 DMOUSE int 68 lastmx int 69 mouse draw.Mouse 70 newscreen bool 71 timerc <-chan time.Time 72 suspc chan bool 73 mousec chan draw.Mouse 74 kbdc chan rune 75 mousectl *draw.Mousectl 76 kbdctl *draw.Keyboardctl 77 suspended bool 78 tsleep int 79 piece *Piece 80 pieces []Piece 81 ) 82 83 type Piece struct { 84 rot int 85 tx int 86 sz image.Point 87 d []image.Point 88 left *Piece 89 right *Piece 90 } 91 92 var txbits = [NCOL][32]byte{ 93 [32]byte{0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, 94 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, 95 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, 96 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF}, 97 [32]byte{0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, 98 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, 99 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, 100 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77}, 101 [32]byte{0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 102 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 103 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 104 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55}, 105 [32]byte{0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 106 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 107 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 108 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55}, 109 [32]byte{0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 110 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 111 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 112 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88}, 113 [32]byte{0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 114 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 115 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 116 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00}, 117 [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 118 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 119 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 120 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, 121 [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 122 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 123 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 124 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, 125 [32]byte{0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 126 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 127 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 128 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC}, 129 [32]byte{0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 130 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 131 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, 132 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33}, 133 } 134 135 var txpix = [NCOL]draw.Color{ 136 draw.Yellow, /* yellow */ 137 draw.Cyan, /* cyan */ 138 draw.Green, /* lime green */ 139 draw.GreyBlue, /* slate */ 140 draw.Red, /* red */ 141 draw.GreyGreen, /* olive green */ 142 draw.Blue, /* blue */ 143 0xFF55AAFF, /* pink */ 144 0xFFAAFFFF, /* lavender */ 145 0xBB005DFF, /* maroon */ 146 } 147 148 var tx [NCOL]*draw.Image 149 150 func movemouse() int { 151 mouse.Point = image.Pt(rboard.Min.X+rboard.Dx()/2, rboard.Min.Y+rboard.Dy()/2) 152 //mousectl.MoveTo(mouse.Point) 153 return mouse.X 154 } 155 156 func warp(p image.Point, x int) int { 157 if !suspended && piece != nil { 158 x = pos.X + piece.sz.X*pcsz/2 159 if p.Y < rboard.Min.Y { 160 p.Y = rboard.Min.Y 161 } 162 if p.Y >= rboard.Max.Y { 163 p.Y = rboard.Max.Y - 1 164 } 165 //mousectl.MoveTo(image.Pt(x, p.Y)) 166 } 167 return x 168 } 169 170 func initPieces() { 171 for i := range pieces { 172 p := &pieces[i] 173 if p.rot == 3 { 174 p.right = &pieces[i-3] 175 } else { 176 p.right = &pieces[i+1] 177 } 178 if p.rot == 0 { 179 p.left = &pieces[i+3] 180 } else { 181 p.left = &pieces[i-1] 182 } 183 } 184 } 185 186 func collide(pt image.Point, p *Piece) bool { 187 pt.X = (pt.X - rboard.Min.X) / pcsz 188 pt.Y = (pt.Y - rboard.Min.Y) / pcsz 189 for _, q := range p.d { 190 pt.X += q.X 191 pt.Y += q.Y 192 if pt.X < 0 || pt.X >= NX || pt.Y < 0 || pt.Y >= NY { 193 return true 194 } 195 if board[pt.Y][pt.X] != 0 { 196 return true 197 } 198 } 199 return false 200 } 201 202 func collider(pt, pmax image.Point) bool { 203 pi := (pt.X - rboard.Min.X) / pcsz 204 pj := (pt.Y - rboard.Min.Y) / pcsz 205 n := pmax.X / pcsz 206 m := pmax.Y/pcsz + 1 207 for i := pi; i < pi+n && i < NX; i++ { 208 for j := pj; j < pj+m && j < NY; j++ { 209 if board[j][i] != 0 { 210 return true 211 } 212 } 213 } 214 return false 215 } 216 217 func setpiece(p *Piece) { 218 bb.Draw(bb.R, display.White, nil, draw.ZP) 219 bbmask.Draw(bb.R, display.Transparent, nil, draw.ZP) 220 br = image.Rect(0, 0, 0, 0) 221 br2 = br 222 piece = p 223 if p == nil { 224 return 225 } 226 var op image.Point 227 var r image.Rectangle 228 r.Min = bb.R.Min 229 for i, pt := range p.d { 230 r.Min.X += pt.X * pcsz 231 r.Min.Y += pt.Y * pcsz 232 r.Max.X = r.Min.X + pcsz 233 r.Max.Y = r.Min.Y + pcsz 234 if i == 0 { 235 bb.Draw(r, display.Black, nil, draw.ZP) 236 bb.Draw(r.Inset(1), tx[piece.tx], nil, draw.ZP) 237 bbmask.Draw(r, display.Opaque, nil, draw.ZP) 238 op = r.Min 239 } else { 240 bb.Draw(r, bb, nil, op) 241 bbmask.Draw(r, bbmask, nil, op) 242 } 243 if br.Max.X < r.Max.X { 244 br.Max.X = r.Max.X 245 } 246 if br.Max.Y < r.Max.Y { 247 br.Max.Y = r.Max.Y 248 } 249 } 250 br.Max = br.Max.Sub(bb.R.Min) 251 delta := image.Pt(0, DY) 252 br2.Max = br.Max.Add(delta) 253 r = br.Add(bb2.R.Min) 254 r2 := br2.Add(bb2.R.Min) 255 bb2.Draw(r2, display.White, nil, draw.ZP) 256 bb2.Draw(r.Add(delta), bb, nil, bb.R.Min) 257 bb2mask.Draw(r2, display.Transparent, nil, draw.ZP) 258 bb2mask.Draw(r, display.Opaque, bbmask, bb.R.Min) 259 bb2mask.Draw(r.Add(delta), display.Opaque, bbmask, bb.R.Min) 260 } 261 262 func drawpiece() { 263 screen.Draw(br.Add(pos), bb, bbmask, bb.R.Min) 264 if suspended { 265 screen.Draw(br.Add(pos), display.White, whitemask, draw.ZP) 266 } 267 } 268 269 func undrawpiece() { 270 var mask *draw.Image 271 if collider(pos, br.Max) { 272 mask = bbmask 273 } 274 screen.Draw(br.Add(pos), display.White, mask, bb.R.Min) 275 } 276 277 func rest() { 278 pt := pos.Sub(rboard.Min).Div(pcsz) 279 for _, p := range piece.d { 280 pt.X += p.X 281 pt.Y += p.Y 282 board[pt.Y][pt.X] = byte(piece.tx + 16) 283 } 284 } 285 286 func canfit(p *Piece) bool { 287 var dx = [...]int{0, -1, 1, -2, 2, -3, 3, 4, -4} 288 j := N + 1 289 if j >= 4 { 290 j = p.sz.X 291 if j < p.sz.Y { 292 j = p.sz.Y 293 } 294 j = 2*j - 1 295 } 296 for i := 0; i < j; i++ { 297 var z image.Point 298 z.X = pos.X + dx[i]*pcsz 299 z.Y = pos.Y 300 if !collide(z, p) { 301 z.Y = pos.Y + pcsz - 1 302 if !collide(z, p) { 303 undrawpiece() 304 pos.X = z.X 305 return true 306 } 307 } 308 } 309 return false 310 } 311 312 func score(p int) { 313 points += p 314 buf := fmt.Sprintf("%.6d", points) 315 screen.Draw(image.Rectangle{pscore, pscore.Add(scoresz)}, display.White, nil, draw.ZP) 316 screen.String(pscore, display.Black, draw.ZP, display.Font, buf) 317 } 318 319 func drawsq(b *draw.Image, p image.Point, ptx int) { 320 var r image.Rectangle 321 r.Min = p 322 r.Max.X = r.Min.X + pcsz 323 r.Max.Y = r.Min.Y + pcsz 324 b.Draw(r, display.Black, nil, draw.ZP) 325 b.Draw(r.Inset(1), tx[ptx], nil, draw.ZP) 326 } 327 328 func drawboard() { 329 screen.Border(rboard.Inset(-2), 2, display.Black, draw.ZP) 330 screen.Draw(image.Rect(rboard.Min.X, rboard.Min.Y-2, rboard.Max.X, rboard.Min.Y), 331 display.White, nil, draw.ZP) 332 for i := 0; i < NY; i++ { 333 for j := 0; j < NX; j++ { 334 if board[i][j] != 0 { 335 drawsq(screen, image.Pt(rboard.Min.X+j*pcsz, rboard.Min.Y+i*pcsz), int(board[i][j]-16)) 336 } 337 } 338 } 339 score(0) 340 if suspended { 341 screen.Draw(screenr, display.White, whitemask, draw.ZP) 342 } 343 } 344 345 func choosepiece() { 346 for { 347 i := rand.Intn(len(pieces)) 348 setpiece(&pieces[i]) 349 pos = rboard.Min 350 pos.X += rand.Intn(NX) * pcsz 351 if !collide(image.Pt(pos.X, pos.Y+pcsz-DY), piece) { 352 break 353 } 354 } 355 drawpiece() 356 display.Flush() 357 } 358 359 func movepiece() bool { 360 var mask *draw.Image 361 if collide(image.Pt(pos.X, pos.Y+pcsz), piece) { 362 return false 363 } 364 if collider(pos, br2.Max) { 365 mask = bb2mask 366 } 367 screen.Draw(br2.Add(pos), bb2, mask, bb2.R.Min) 368 pos.Y += DY 369 display.Flush() 370 return true 371 } 372 373 func suspend(s bool) { 374 suspended = s 375 /* 376 if suspended { 377 setcursor(mousectl, &whitearrow); 378 } else { 379 setcursor(mousectl, nil); 380 } 381 */ 382 if !suspended { 383 drawpiece() 384 } 385 drawboard() 386 display.Flush() 387 } 388 389 func pause(t int) { 390 display.Flush() 391 for { 392 select { 393 case s := <-suspc: 394 if !suspended && s { 395 suspend(true) 396 } else if suspended && !s { 397 suspend(false) 398 lastmx = warp(mouse.Point, lastmx) 399 } 400 case <-timerc: 401 if suspended { 402 break 403 } 404 t -= tsleep 405 if t < 0 { 406 return 407 } 408 case <-mousectl.Resize: 409 redraw(true) 410 case mouse = <-mousec: 411 case <-kbdc: 412 } 413 } 414 } 415 416 func horiz() bool { 417 var lev [MAXN]int 418 h := 0 419 for i := 0; i < NY; i++ { 420 for j := 0; board[i][j] != 0; j++ { 421 if j == NX-1 { 422 lev[h] = i 423 h++ 424 break 425 } 426 } 427 } 428 if h == 0 { 429 return false 430 } 431 r := rboard 432 newscreen = false 433 for j := 0; j < h; j++ { 434 r.Min.Y = rboard.Min.Y + lev[j]*pcsz 435 r.Max.Y = r.Min.Y + pcsz 436 screen.Draw(r, display.White, whitemask, draw.ZP) 437 display.Flush() 438 } 439 for i := 0; i < 3; i++ { 440 pause(250) 441 if newscreen { 442 drawboard() 443 break 444 } 445 for j := 0; j < h; j++ { 446 r.Min.Y = rboard.Min.Y + lev[j]*pcsz 447 r.Max.Y = r.Min.Y + pcsz 448 screen.Draw(r, display.White, whitemask, draw.ZP) 449 } 450 display.Flush() 451 } 452 r = rboard 453 for j := 0; j < h; j++ { 454 i := NY - lev[j] - 1 455 score(250 + 10*i*i) 456 r.Min.Y = rboard.Min.Y 457 r.Max.Y = rboard.Min.Y + lev[j]*pcsz 458 screen.Draw(r.Add(image.Pt(0, pcsz)), screen, nil, r.Min) 459 r.Max.Y = rboard.Min.Y + pcsz 460 screen.Draw(r, display.White, nil, draw.ZP) 461 for k := lev[j] - 1; k >= 0; k-- { 462 board[k+1] = board[k] 463 } 464 board[0] = [NX]byte{} 465 } 466 display.Flush() 467 return true 468 } 469 470 func mright() { 471 if !collide(image.Pt(pos.X+pcsz, pos.Y), piece) && !collide(image.Pt(pos.X+pcsz, pos.Y+pcsz-DY), piece) { 472 undrawpiece() 473 pos.X += pcsz 474 drawpiece() 475 display.Flush() 476 } 477 } 478 479 func mleft() { 480 if !collide(image.Pt(pos.X-pcsz, pos.Y), piece) && !collide(image.Pt(pos.X-pcsz, pos.Y+pcsz-DY), piece) { 481 undrawpiece() 482 pos.X -= pcsz 483 drawpiece() 484 display.Flush() 485 } 486 } 487 488 func rright() { 489 if canfit(piece.right) { 490 setpiece(piece.right) 491 drawpiece() 492 display.Flush() 493 } 494 } 495 496 func rleft() { 497 if canfit(piece.left) { 498 setpiece(piece.left) 499 drawpiece() 500 display.Flush() 501 } 502 } 503 504 var fusst = 0 505 506 func drop(f bool) bool { 507 if f { 508 score(5 * (rboard.Max.Y - pos.Y) / pcsz) 509 for movepiece() { 510 } 511 } 512 fusst = 0 513 rest() 514 if pos.Y == rboard.Min.Y && !horiz() { 515 return true 516 } 517 horiz() 518 setpiece(nil) 519 pause(1500) 520 choosepiece() 521 lastmx = warp(mouse.Point, lastmx) 522 return false 523 } 524 525 func play() { 526 var om draw.Mouse 527 dt = 64 528 lastmx = -1 529 lastmx = movemouse() 530 choosepiece() 531 lastmx = warp(mouse.Point, lastmx) 532 for { 533 select { 534 case mouse = <-mousec: 535 if suspended { 536 om = mouse 537 break 538 } 539 if lastmx < 0 { 540 lastmx = mouse.X 541 } 542 if mouse.X > lastmx+DMOUSE { 543 mright() 544 lastmx = mouse.X 545 } 546 if mouse.X < lastmx-DMOUSE { 547 mleft() 548 lastmx = mouse.X 549 } 550 if mouse.Buttons&^om.Buttons&1 == 1 { 551 rleft() 552 } 553 if mouse.Buttons&^om.Buttons&2 == 2 { 554 if drop(true) { 555 return 556 } 557 } 558 if mouse.Buttons&^om.Buttons&4 == 4 { 559 rright() 560 } 561 om = mouse 562 563 case s := <-suspc: 564 if !suspended && s { 565 suspend(true) 566 } else if suspended && !s { 567 suspend(false) 568 lastmx = warp(mouse.Point, lastmx) 569 } 570 571 case <-mousectl.Resize: 572 redraw(true) 573 574 case r := <-kbdc: 575 if suspended { 576 break 577 } 578 switch r { 579 case 'f', ';': 580 mright() 581 case 'a', 'j': 582 mleft() 583 case 'd', 'l': 584 rright() 585 case 's', 'k': 586 rleft() 587 case ' ': 588 if drop(true) { 589 return 590 } 591 } 592 593 case <-timerc: 594 if suspended { 595 break 596 } 597 dt -= tsleep 598 if dt < 0 { 599 i := 1 600 dt = 16 * (points + rand.Intn(10000) - 5000) / 10000 601 if dt >= 32 { 602 i += (dt - 32) / 16 603 dt = 32 604 } 605 dt = 52 - dt 606 for ; i > 0; i-- { 607 if movepiece() { 608 continue 609 } 610 fusst++ 611 if fusst == 40 { 612 if drop(false) { 613 return 614 } 615 break 616 } 617 } 618 } 619 } 620 } 621 } 622 623 func suspproc() { 624 s := false 625 for { 626 select { 627 case mouse = <-mousectl.C: 628 mousec <- mouse 629 case r := <-kbdctl.C: 630 switch r { 631 case 'q', 'Q', 0x04, 0x7F: 632 os.Exit(0) 633 default: 634 if s { 635 s = false 636 suspc <- s 637 break 638 } 639 switch r { 640 case 'z', 'Z', 'p', 'P', 0x1B: 641 s = true 642 suspc <- s 643 default: 644 kbdc <- r 645 } 646 } 647 } 648 } 649 } 650 651 func redraw(new bool) { 652 if new { 653 if err := display.Attach(draw.RefMesg); err != nil { 654 log.Fatalf("can't reattach to window: %v", err) 655 } 656 } 657 658 r := screen.R 659 pos.X = (pos.X - rboard.Min.X) / pcsz 660 pos.Y = (pos.Y - rboard.Min.Y) / pcsz 661 dx := r.Max.X - r.Min.X 662 dy := r.Max.Y - r.Min.Y - 2*32 663 DY = dx / NX 664 if DY > dy/NY { 665 DY = dy / NY 666 } 667 DY /= 8 668 if DY > 4 { 669 DY = 4 670 } 671 pcsz = DY * 8 672 DMOUSE = pcsz / 3 673 if pcsz < 8 { 674 log.Fatalf("screen too small: %d", pcsz) 675 } 676 rboard = screenr 677 rboard.Min.X += (dx - pcsz*NX) / 2 678 rboard.Min.Y += (dy-pcsz*NY)/2 + 32 679 rboard.Max.X = rboard.Min.X + NX*pcsz 680 rboard.Max.Y = rboard.Min.Y + NY*pcsz 681 pscore.X = rboard.Min.X + 8 682 pscore.Y = rboard.Min.Y - 32 683 scoresz = display.Font.StringSize("000000") 684 pos.X = pos.X*pcsz + rboard.Min.X 685 pos.Y = pos.Y*pcsz + rboard.Min.Y 686 if bb != nil { 687 bb.Free() 688 bbmask.Free() 689 bb2.Free() 690 bb2mask.Free() 691 } 692 bb, _ = display.AllocImage(image.Rect(0, 0, N*pcsz, N*pcsz), screen.Pix, false, 0) 693 bbmask, _ = display.AllocImage(image.Rect(0, 0, N*pcsz, N*pcsz), draw.GREY1, false, 0) 694 bb2, _ = display.AllocImage(image.Rect(0, 0, N*pcsz, N*pcsz+DY), screen.Pix, false, 0) 695 bb2mask, _ = display.AllocImage(image.Rect(0, 0, N*pcsz, N*pcsz+DY), draw.GREY1, false, 0) 696 screen.Draw(screenr, display.White, nil, draw.ZP) 697 drawboard() 698 setpiece(piece) 699 if piece != nil { 700 drawpiece() 701 } 702 lastmx = movemouse() 703 newscreen = true 704 display.Flush() 705 } 706 707 func Play(pp []Piece, d *draw.Display) { 708 pieces = pp 709 N = len(pieces[0].d) 710 initPieces() 711 display = d 712 screen = d.ScreenImage 713 714 mousectl = d.InitMouse() 715 kbdctl = d.InitKeyboard() 716 rand.Seed(int64(time.Now().UnixNano() % (1e9 - 1))) 717 for i, col := range txpix { 718 tx[i], _ = d.AllocImage(image.Rect(0, 0, 1, 1), screen.Pix, true, col) 719 } 720 whitemask, _ = display.AllocImage(image.Rect(0, 0, 1, 1), draw.ARGB32, true, 0x7F7F7F7F) 721 tsleep = 50 722 timerc = time.Tick(time.Duration(tsleep/2) * time.Millisecond) 723 suspc = make(chan bool) 724 mousec = make(chan draw.Mouse) 725 kbdc = make(chan rune) 726 go suspproc() 727 redraw(false) 728 play() 729 }