| // games/4s - a tetris clone |
| // |
| // Derived from Plan 9's /sys/src/games/xs.c |
| // http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c |
| // |
| // Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved. |
| // Portions Copyright 2009 The Go Authors. All Rights Reserved. |
| // Distributed under the terms of the Lucent Public License Version 1.02 |
| // See http://plan9.bell-labs.com/plan9/license.html |
| |
| /* |
| * engine for 4s, 5s, etc |
| */ |
| |
| package main |
| |
| import ( |
| "exp/draw"; |
| "image"; |
| "log"; |
| "os"; |
| "rand"; |
| "time"; |
| ) |
| |
| /* |
| Cursor whitearrow = { |
| {0, 0}, |
| {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, |
| 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, |
| 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, |
| 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }, |
| {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, |
| 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, |
| 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, |
| 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, } |
| }; |
| */ |
| |
| const ( |
| CNone = 0; |
| CBounds = 1; |
| CPiece = 2; |
| NX = 10; |
| NY = 20; |
| |
| NCOL = 10; |
| |
| MAXN = 5; |
| ) |
| |
| var ( |
| N int; |
| display draw.Context; |
| screen draw.Image; |
| screenr draw.Rectangle; |
| board [NY][NX]byte; |
| rboard draw.Rectangle; |
| pscore draw.Point; |
| scoresz draw.Point; |
| pcsz = 32; |
| pos draw.Point; |
| bbr, bb2r draw.Rectangle; |
| bb, bbmask, bb2, bb2mask *image.RGBA; |
| whitemask image.Image; |
| br, br2 draw.Rectangle; |
| points int; |
| dt int; |
| DY int; |
| DMOUSE int; |
| lastmx int; |
| mouse draw.Mouse; |
| newscreen bool; |
| timerc <-chan int64; |
| suspc chan bool; |
| mousec chan draw.Mouse; |
| resizec <-chan bool; |
| kbdc chan int; |
| suspended bool; |
| tsleep int; |
| piece *Piece; |
| pieces []Piece; |
| ) |
| |
| type Piece struct { |
| rot int; |
| tx int; |
| sz draw.Point; |
| d []draw.Point; |
| left *Piece; |
| right *Piece; |
| } |
| |
| var txbits = [NCOL][32]byte{ |
| [32]byte{0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, |
| 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, |
| 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, |
| 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF, |
| }, |
| [32]byte{0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, |
| 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, |
| 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, |
| 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77, |
| }, |
| [32]byte{0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| }, |
| [32]byte{0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, |
| }, |
| [32]byte{0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, |
| 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, |
| 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, |
| 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, |
| }, |
| [32]byte{0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, |
| 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, |
| 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, |
| 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, |
| }, |
| [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| }, |
| [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, |
| }, |
| [32]byte{0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, |
| 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, |
| 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, |
| 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, |
| }, |
| [32]byte{0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, |
| 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, |
| 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, |
| 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33, |
| }, |
| } |
| |
| var txpix = [NCOL]draw.Color{ |
| draw.Yellow, /* yellow */ |
| draw.Cyan, /* cyan */ |
| draw.Green, /* lime green */ |
| draw.GreyBlue, /* slate */ |
| draw.Red, /* red */ |
| draw.GreyGreen, /* olive green */ |
| draw.Blue, /* blue */ |
| draw.Color(0xFF55AAFF), /* pink */ |
| draw.Color(0xFFAAFFFF), /* lavender */ |
| draw.Color(0xBB005DFF), /* maroon */ |
| } |
| |
| func movemouse() int { |
| //mouse.draw.Point = draw.Pt(rboard.Min.X + rboard.Dx()/2, rboard.Min.Y + rboard.Dy()/2); |
| //moveto(mousectl, mouse.Xy); |
| return mouse.X |
| } |
| |
| func warp(p draw.Point, x int) int { |
| if !suspended && piece != nil { |
| x = pos.X + piece.sz.X*pcsz/2; |
| if p.Y < rboard.Min.Y { |
| p.Y = rboard.Min.Y |
| } |
| if p.Y >= rboard.Max.Y { |
| p.Y = rboard.Max.Y - 1 |
| } |
| //moveto(mousectl, draw.Pt(x, p.Y)); |
| } |
| return x; |
| } |
| |
| func initPieces() { |
| for i := range pieces { |
| p := &pieces[i]; |
| if p.rot == 3 { |
| p.right = &pieces[i-3] |
| } else { |
| p.right = &pieces[i+1] |
| } |
| if p.rot == 0 { |
| p.left = &pieces[i+3] |
| } else { |
| p.left = &pieces[i-1] |
| } |
| } |
| } |
| |
| func collide(pt draw.Point, p *Piece) bool { |
| pt.X = (pt.X - rboard.Min.X) / pcsz; |
| pt.Y = (pt.Y - rboard.Min.Y) / pcsz; |
| for _, q := range p.d { |
| pt.X += q.X; |
| pt.Y += q.Y; |
| if pt.X < 0 || pt.X >= NX || pt.Y < 0 || pt.Y >= NY { |
| return true; |
| continue; |
| } |
| if board[pt.Y][pt.X] != 0 { |
| return true |
| } |
| } |
| return false; |
| } |
| |
| func collider(pt, pmax draw.Point) bool { |
| pi := (pt.X - rboard.Min.X) / pcsz; |
| pj := (pt.Y - rboard.Min.Y) / pcsz; |
| n := pmax.X / pcsz; |
| m := pmax.Y/pcsz + 1; |
| for i := pi; i < pi+n && i < NX; i++ { |
| for j := pj; j < pj+m && j < NY; j++ { |
| if board[j][i] != 0 { |
| return true |
| } |
| } |
| } |
| return false; |
| } |
| |
| func setpiece(p *Piece) { |
| draw.Draw(bb, bbr, draw.White, nil, draw.ZP); |
| draw.Draw(bbmask, bbr, draw.Transparent, nil, draw.ZP); |
| br = draw.Rect(0, 0, 0, 0); |
| br2 = br; |
| piece = p; |
| if p == nil { |
| return |
| } |
| var op draw.Point; |
| var r draw.Rectangle; |
| r.Min = bbr.Min; |
| for i, pt := range p.d { |
| r.Min.X += pt.X * pcsz; |
| r.Min.Y += pt.Y * pcsz; |
| r.Max.X = r.Min.X + pcsz; |
| r.Max.Y = r.Min.Y + pcsz; |
| if i == 0 { |
| draw.Draw(bb, r, draw.Black, nil, draw.ZP); |
| draw.Draw(bb, r.Inset(1), txpix[piece.tx], nil, draw.ZP); |
| draw.Draw(bbmask, r, draw.Opaque, nil, draw.ZP); |
| op = r.Min; |
| } else { |
| draw.Draw(bb, r, bb, nil, op); |
| draw.Draw(bbmask, r, bbmask, nil, op); |
| } |
| if br.Max.X < r.Max.X { |
| br.Max.X = r.Max.X |
| } |
| if br.Max.Y < r.Max.Y { |
| br.Max.Y = r.Max.Y |
| } |
| } |
| br.Max = br.Max.Sub(bbr.Min); |
| delta := draw.Pt(0, DY); |
| br2.Max = br.Max.Add(delta); |
| r = br.Add(bb2r.Min); |
| r2 := br2.Add(bb2r.Min); |
| draw.Draw(bb2, r2, draw.White, nil, draw.ZP); |
| draw.Draw(bb2, r.Add(delta), bb, nil, bbr.Min); |
| draw.Draw(bb2mask, r2, draw.Transparent, nil, draw.ZP); |
| draw.Draw(bb2mask, r, draw.Opaque, bbmask, bbr.Min); |
| draw.Draw(bb2mask, r.Add(delta), draw.Opaque, bbmask, bbr.Min); |
| } |
| |
| func drawpiece() { |
| draw.Draw(screen, br.Add(pos), bb, bbmask, bbr.Min); |
| if suspended { |
| draw.Draw(screen, br.Add(pos), draw.White, whitemask, draw.ZP) |
| } |
| } |
| |
| func undrawpiece() { |
| var mask image.Image; |
| if collider(pos, br.Max) { |
| mask = bbmask |
| } |
| draw.Draw(screen, br.Add(pos), draw.White, mask, bbr.Min); |
| } |
| |
| func rest() { |
| pt := pos.Sub(rboard.Min).Div(pcsz); |
| for _, p := range piece.d { |
| pt.X += p.X; |
| pt.Y += p.Y; |
| board[pt.Y][pt.X] = byte(piece.tx + 16); |
| } |
| } |
| |
| func canfit(p *Piece) bool { |
| var dx = [...]int{0, -1, 1, -2, 2, -3, 3, 4, -4}; |
| j := N + 1; |
| if j >= 4 { |
| j = p.sz.X; |
| if j < p.sz.Y { |
| j = p.sz.Y |
| } |
| j = 2*j - 1; |
| } |
| for i := 0; i < j; i++ { |
| var z draw.Point; |
| z.X = pos.X + dx[i]*pcsz; |
| z.Y = pos.Y; |
| if !collide(z, p) { |
| z.Y = pos.Y + pcsz - 1; |
| if !collide(z, p) { |
| undrawpiece(); |
| pos.X = z.X; |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| func score(p int) { |
| points += p |
| // snprint(buf, sizeof(buf), "%.6ld", points); |
| // draw.Draw(screen, draw.Rpt(pscore, pscore.Add(scoresz)), draw.White, nil, draw.ZP); |
| // string(screen, pscore, draw.Black, draw.ZP, font, buf); |
| } |
| |
| func drawsq(b draw.Image, p draw.Point, ptx int) { |
| var r draw.Rectangle; |
| r.Min = p; |
| r.Max.X = r.Min.X + pcsz; |
| r.Max.Y = r.Min.Y + pcsz; |
| draw.Draw(b, r, draw.Black, nil, draw.ZP); |
| draw.Draw(b, r.Inset(1), txpix[ptx], nil, draw.ZP); |
| } |
| |
| func drawboard() { |
| draw.Border(screen, rboard.Inset(-2), 2, draw.Black, draw.ZP); |
| draw.Draw(screen, draw.Rect(rboard.Min.X, rboard.Min.Y-2, rboard.Max.X, rboard.Min.Y), |
| draw.White, nil, draw.ZP); |
| for i := 0; i < NY; i++ { |
| for j := 0; j < NX; j++ { |
| if board[i][j] != 0 { |
| drawsq(screen, draw.Pt(rboard.Min.X+j*pcsz, rboard.Min.Y+i*pcsz), int(board[i][j]-16)) |
| } |
| } |
| } |
| score(0); |
| if suspended { |
| draw.Draw(screen, screenr, draw.White, whitemask, draw.ZP) |
| } |
| } |
| |
| func choosepiece() { |
| for { |
| i := rand.Intn(len(pieces)); |
| setpiece(&pieces[i]); |
| pos = rboard.Min; |
| pos.X += rand.Intn(NX) * pcsz; |
| if !collide(draw.Pt(pos.X, pos.Y+pcsz-DY), piece) { |
| break |
| } |
| } |
| drawpiece(); |
| display.FlushImage(); |
| } |
| |
| func movepiece() bool { |
| var mask image.Image; |
| if collide(draw.Pt(pos.X, pos.Y+pcsz), piece) { |
| return false |
| } |
| if collider(pos, br2.Max) { |
| mask = bb2mask |
| } |
| draw.Draw(screen, br2.Add(pos), bb2, mask, bb2r.Min); |
| pos.Y += DY; |
| display.FlushImage(); |
| return true; |
| } |
| |
| func suspend(s bool) { |
| suspended = s; |
| /* |
| if suspended { |
| setcursor(mousectl, &whitearrow); |
| } else { |
| setcursor(mousectl, nil); |
| } |
| */ |
| if !suspended { |
| drawpiece() |
| } |
| drawboard(); |
| display.FlushImage(); |
| } |
| |
| func pause(t int) { |
| display.FlushImage(); |
| for { |
| select { |
| case s := <-suspc: |
| if !suspended && s { |
| suspend(true) |
| } else if suspended && !s { |
| suspend(false); |
| lastmx = warp(mouse.Point, lastmx); |
| } |
| case <-timerc: |
| if suspended { |
| break |
| } |
| t -= tsleep; |
| if t < 0 { |
| return |
| } |
| case <-resizec: |
| //redraw(true); |
| case mouse = <-mousec: |
| case <-kbdc: |
| } |
| } |
| } |
| |
| func horiz() bool { |
| var lev [MAXN]int; |
| h := 0; |
| for i := 0; i < NY; i++ { |
| for j := 0; board[i][j] != 0; j++ { |
| if j == NX-1 { |
| lev[h] = i; |
| h++; |
| break; |
| } |
| } |
| } |
| if h == 0 { |
| return false |
| } |
| r := rboard; |
| newscreen = false; |
| for j := 0; j < h; j++ { |
| r.Min.Y = rboard.Min.Y + lev[j]*pcsz; |
| r.Max.Y = r.Min.Y + pcsz; |
| draw.Draw(screen, r, draw.White, whitemask, draw.ZP); |
| display.FlushImage(); |
| } |
| PlaySound(whoosh); |
| for i := 0; i < 3; i++ { |
| pause(250); |
| if newscreen { |
| drawboard(); |
| break; |
| } |
| for j := 0; j < h; j++ { |
| r.Min.Y = rboard.Min.Y + lev[j]*pcsz; |
| r.Max.Y = r.Min.Y + pcsz; |
| draw.Draw(screen, r, draw.White, whitemask, draw.ZP); |
| } |
| display.FlushImage(); |
| } |
| r = rboard; |
| for j := 0; j < h; j++ { |
| i := NY - lev[j] - 1; |
| score(250 + 10*i*i); |
| r.Min.Y = rboard.Min.Y; |
| r.Max.Y = rboard.Min.Y + lev[j]*pcsz; |
| draw.Draw(screen, r.Add(draw.Pt(0, pcsz)), screen, nil, r.Min); |
| r.Max.Y = rboard.Min.Y + pcsz; |
| draw.Draw(screen, r, draw.White, nil, draw.ZP); |
| for k := lev[j] - 1; k >= 0; k-- { |
| board[k+1] = board[k] |
| } |
| board[0] = [NX]byte{}; |
| } |
| display.FlushImage(); |
| return true; |
| } |
| |
| func mright() { |
| if !collide(draw.Pt(pos.X+pcsz, pos.Y), piece) && |
| !collide(draw.Pt(pos.X+pcsz, pos.Y+pcsz-DY), piece) { |
| undrawpiece(); |
| pos.X += pcsz; |
| drawpiece(); |
| display.FlushImage(); |
| } |
| } |
| |
| func mleft() { |
| if !collide(draw.Pt(pos.X-pcsz, pos.Y), piece) && |
| !collide(draw.Pt(pos.X-pcsz, pos.Y+pcsz-DY), piece) { |
| undrawpiece(); |
| pos.X -= pcsz; |
| drawpiece(); |
| display.FlushImage(); |
| } |
| } |
| |
| func rright() { |
| if canfit(piece.right) { |
| setpiece(piece.right); |
| drawpiece(); |
| display.FlushImage(); |
| } |
| } |
| |
| func rleft() { |
| if canfit(piece.left) { |
| setpiece(piece.left); |
| drawpiece(); |
| display.FlushImage(); |
| } |
| } |
| |
| var fusst = 0 |
| |
| func drop(f bool) bool { |
| if f { |
| score(5 * (rboard.Max.Y - pos.Y) / pcsz); |
| for movepiece() { |
| } |
| } |
| fusst = 0; |
| rest(); |
| if pos.Y == rboard.Min.Y && !horiz() { |
| return true |
| } |
| horiz(); |
| setpiece(nil); |
| pause(1500); |
| choosepiece(); |
| lastmx = warp(mouse.Point, lastmx); |
| return false; |
| } |
| |
| func play() { |
| var om draw.Mouse; |
| dt = 64; |
| lastmx = -1; |
| lastmx = movemouse(); |
| choosepiece(); |
| lastmx = warp(mouse.Point, lastmx); |
| for { |
| select { |
| case mouse = <-mousec: |
| if suspended { |
| om = mouse; |
| break; |
| } |
| if lastmx < 0 { |
| lastmx = mouse.X |
| } |
| if mouse.X > lastmx+DMOUSE { |
| mright(); |
| lastmx = mouse.X; |
| } |
| if mouse.X < lastmx-DMOUSE { |
| mleft(); |
| lastmx = mouse.X; |
| } |
| if mouse.Buttons&^om.Buttons&1 == 1 { |
| rleft() |
| } |
| if mouse.Buttons&^om.Buttons&2 == 2 { |
| if drop(true) { |
| return |
| } |
| } |
| if mouse.Buttons&^om.Buttons&4 == 4 { |
| rright() |
| } |
| om = mouse; |
| |
| case s := <-suspc: |
| if !suspended && s { |
| suspend(true) |
| } else if suspended && !s { |
| suspend(false); |
| lastmx = warp(mouse.Point, lastmx); |
| } |
| |
| case <-resizec: |
| //redraw(true); |
| |
| case r := <-kbdc: |
| if suspended { |
| break |
| } |
| switch r { |
| case 'f', ';': |
| mright() |
| case 'a', 'j': |
| mleft() |
| case 'd', 'l': |
| rright() |
| case 's', 'k': |
| rleft() |
| case ' ': |
| if drop(true) { |
| return |
| } |
| } |
| |
| case <-timerc: |
| if suspended { |
| break |
| } |
| dt -= tsleep; |
| if dt < 0 { |
| i := 1; |
| dt = 16 * (points + rand.Intn(10000) - 5000) / 10000; |
| if dt >= 32 { |
| i += (dt - 32) / 16; |
| dt = 32; |
| } |
| dt = 52 - dt; |
| for ; i > 0; i-- { |
| if movepiece() { |
| continue |
| } |
| fusst++; |
| if fusst == 40 { |
| if drop(false) { |
| return |
| } |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| func suspproc() { |
| mc := display.MouseChan(); |
| kc := display.KeyboardChan(); |
| |
| s := false; |
| for { |
| select { |
| case mouse = <-mc: |
| mousec <- mouse |
| case r := <-kc: |
| switch r { |
| case 'q', 'Q', 0x04, 0x7F: |
| os.Exit(0) |
| default: |
| if s { |
| s = false; |
| suspc <- s; |
| break; |
| } |
| switch r { |
| case 'z', 'Z', 'p', 'P', 0x1B: |
| s = true; |
| suspc <- s; |
| default: |
| kbdc <- r |
| } |
| } |
| } |
| } |
| } |
| |
| func redraw(new bool) { |
| // if new && getwindow(display, Refmesg) < 0 { |
| // sysfatal("can't reattach to window"); |
| // } |
| r := draw.Rect(0, 0, screen.Width(), screen.Height()); |
| pos.X = (pos.X - rboard.Min.X) / pcsz; |
| pos.Y = (pos.Y - rboard.Min.Y) / pcsz; |
| dx := r.Max.X - r.Min.X; |
| dy := r.Max.Y - r.Min.Y - 2*32; |
| DY = dx / NX; |
| if DY > dy/NY { |
| DY = dy / NY |
| } |
| DY /= 8; |
| if DY > 4 { |
| DY = 4 |
| } |
| pcsz = DY * 8; |
| DMOUSE = pcsz / 3; |
| if pcsz < 8 { |
| log.Exitf("screen too small: %d", pcsz) |
| } |
| rboard = screenr; |
| rboard.Min.X += (dx - pcsz*NX) / 2; |
| rboard.Min.Y += (dy-pcsz*NY)/2 + 32; |
| rboard.Max.X = rboard.Min.X + NX*pcsz; |
| rboard.Max.Y = rboard.Min.Y + NY*pcsz; |
| pscore.X = rboard.Min.X + 8; |
| pscore.Y = rboard.Min.Y - 32; |
| // scoresz = stringsize(font, "000000"); |
| pos.X = pos.X*pcsz + rboard.Min.X; |
| pos.Y = pos.Y*pcsz + rboard.Min.Y; |
| bbr = draw.Rect(0, 0, N*pcsz, N*pcsz); |
| bb = image.NewRGBA(bbr.Max.X, bbr.Max.Y); |
| bbmask = image.NewRGBA(bbr.Max.X, bbr.Max.Y); // actually just a bitmap |
| bb2r = draw.Rect(0, 0, N*pcsz, N*pcsz+DY); |
| bb2 = image.NewRGBA(bb2r.Dx(), bb2r.Dy()); |
| bb2mask = image.NewRGBA(bb2r.Dx(), bb2r.Dy()); // actually just a bitmap |
| draw.Draw(screen, screenr, draw.White, nil, draw.ZP); |
| drawboard(); |
| setpiece(piece); |
| if piece != nil { |
| drawpiece() |
| } |
| lastmx = movemouse(); |
| newscreen = true; |
| display.FlushImage(); |
| } |
| |
| func quitter(c <-chan bool) { |
| <-c; |
| os.Exit(0); |
| } |
| |
| func Play(pp []Piece, ctxt draw.Context) { |
| display = ctxt; |
| screen = ctxt.Screen(); |
| screenr = draw.Rect(0, 0, screen.Width(), screen.Height()); |
| pieces = pp; |
| N = len(pieces[0].d); |
| initPieces(); |
| rand.Seed(int32(time.Nanoseconds() % (1e9 - 1))); |
| whitemask = draw.White.SetAlpha(0x7F); |
| tsleep = 50; |
| timerc = time.Tick(int64(tsleep/2) * 1e6); |
| suspc = make(chan bool); |
| mousec = make(chan draw.Mouse); |
| resizec = ctxt.ResizeChan(); |
| kbdc = make(chan int); |
| go quitter(ctxt.QuitChan()); |
| go suspproc(); |
| points = 0; |
| redraw(false); |
| play(); |
| } |