├── 2048.go ├── README.md ├── box ├── box.go ├── merge.go ├── print.go ├── transform.go └── win.go ├── demo └── demo.go └── img └── Screenshot.png /2048.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/wangwenbin/2048-go/demo" 5 | ) 6 | 7 | func main() { 8 | demo.Go() 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #2048-go 2 | 3 | ##about 2048-go 4 | 2048 is a famous game by Gabriele Cirulli, I copyed the idea and rewrite it with golang. 5 | 6 | This 2048 runs under terminial. It can run without X under linux. I don't know if it works under DOS, But it works under CMD. The code is cross platform for using golang. 7 | 8 | Thanks for termbox-go. 9 | 10 | This is Gabriele Cirulli's code. 11 | 12 | > https://github.com/gabrielecirulli/2048 13 | 14 | ##Screenshot 15 | 16 | My code works like this. 17 | 18 | ![Screenshot-2048-go](./img/Screenshot.png) 19 | 20 | I have not got 2048 yet. If you get there, share me with your Screenshot. 21 | 22 | 23 | ##Get binnary. 24 | 25 | The binnary is avilable on *gobuild.io*. 26 | 27 | Thanks for gobuild. 28 | 29 | [Down on gobuild.io](http://gobuild.io/download/github.com/wangwenbin/2048-go) 30 | 31 | ##License 32 | 33 | 2048 is licensed under the MIT license. 34 | -------------------------------------------------------------------------------- /box/box.go: -------------------------------------------------------------------------------- 1 | // Package this file just provides another way to merger boxes. 2 | // I test this but I didn't use this because I finished write that fuck on 3 | // before this. I still haven't got the best . 4 | package box 5 | 6 | type Box [4][4]int 7 | 8 | var Score int 9 | var step int 10 | 11 | func Clear() { 12 | Score = 0 13 | step = 0 14 | } 15 | -------------------------------------------------------------------------------- /box/merge.go: -------------------------------------------------------------------------------- 1 | package box 2 | 3 | import ( 4 | "github.com/nsf/termbox-go" 5 | ) 6 | 7 | func (t *Box) MergeAndReturnKey() termbox.Key { 8 | var changed bool 9 | Lable: 10 | changed = false 11 | ev := termbox.PollEvent() 12 | switch ev.Type { 13 | case termbox.EventKey: 14 | switch ev.Key { 15 | case termbox.KeyArrowUp: 16 | changed = t.MergeUP() 17 | case termbox.KeyArrowDown: 18 | changed = t.MergeDwon() 19 | case termbox.KeyArrowLeft: 20 | changed = t.MergeLeft() 21 | case termbox.KeyArrowRight: 22 | changed = t.MergeRight() 23 | case termbox.KeyEsc, termbox.KeyEnter: 24 | changed = true 25 | default: 26 | changed = false 27 | //t.Print(0, 3) 28 | } 29 | if !changed { 30 | goto Lable 31 | } 32 | 33 | case termbox.EventResize: 34 | x, y := termbox.Size() 35 | t.Print(x/2-10, y/2-4) 36 | goto Lable 37 | case termbox.EventError: 38 | panic(ev.Err) 39 | } 40 | step++ 41 | return ev.Key 42 | } 43 | 44 | func (t *Box) MergeUP() bool { 45 | tl := len(t) 46 | changed := false 47 | notfull := false 48 | for i := 0; i < tl; i++ { 49 | 50 | np := tl //the last number needed check, first time use len(t). 51 | n := 0 //count of none 0. 52 | 53 | //clean 0 from top to the last number and move numbers together. 54 | //imag another t that smaller than this, but covered this. 55 | //n after "for" is size of the small t, gives the value of next np. 56 | for x := 0; x < np; x++ { 57 | if t[x][i] != 0 { 58 | t[n][i] = t[x][i] 59 | if n != x { 60 | changed = true 61 | } 62 | n++ 63 | } 64 | } 65 | if n < tl { 66 | notfull = true 67 | } 68 | np = n 69 | //mergeup all the number x that are same with its uper one. 70 | //uper one store 2*x, downer store 0. 71 | for x := 0; x < np-1; x++ { 72 | if t[x][i] == t[x+1][i] { 73 | t[x][i] *= 2 74 | t[x+1][i] = 0 75 | Score += t[x][i] * step 76 | x++ 77 | changed = true 78 | // n-- 79 | } 80 | } 81 | //clean the new added 0 use the same way. 82 | n = 0 83 | for x := 0; x < np; x++ { 84 | if t[x][i] != 0 { 85 | t[n][i] = t[x][i] 86 | n++ 87 | } 88 | } 89 | //cover the unchecked with 0 90 | for x := n; x < tl; x++ { 91 | t[x][i] = 0 92 | } 93 | } 94 | return changed || !notfull 95 | } 96 | func (t *Box) MergeDwon() bool { 97 | t.MirrorV() 98 | changed := t.MergeUP() 99 | t.MirrorV() 100 | return changed 101 | } 102 | func (t *Box) MergeLeft() bool { 103 | t.Right90() 104 | changed := t.MergeUP() 105 | t.Left90() 106 | return changed 107 | } 108 | func (t *Box) MergeRight() bool { 109 | t.Left90() 110 | changed := t.MergeUP() 111 | t.Right90() 112 | return changed 113 | } 114 | -------------------------------------------------------------------------------- /box/print.go: -------------------------------------------------------------------------------- 1 | package box 2 | 3 | import ( 4 | "fmt" 5 | "github.com/nsf/termbox-go" 6 | ) 7 | 8 | func CoverPrintStr(x, y int, str string, fg, bg termbox.Attribute) error { 9 | 10 | //str := "Win,use ESC exit" 11 | xx := x 12 | for n, c := range str { 13 | if c == '\n' { 14 | y++ 15 | xx = x - n - 1 16 | } 17 | termbox.SetCell(xx+n, y, c, fg, bg) 18 | } 19 | termbox.Flush() 20 | return nil 21 | } 22 | 23 | func (t Box) Print(ox, oy int) error { 24 | fg := termbox.ColorYellow 25 | bg := termbox.ColorBlack 26 | termbox.Clear(fg, bg) 27 | str := " SCORE: " + fmt.Sprint(Score) 28 | for n, c := range str { 29 | termbox.SetCell(ox+n, oy-1, c, fg, bg) 30 | } 31 | str = "ESC:exit " + "Enter:replay" 32 | for n, c := range str { 33 | termbox.SetCell(ox+n, oy-2, c, fg, bg) 34 | } 35 | str = "Play with arrow key!" 36 | for n, c := range str { 37 | termbox.SetCell(ox+n, oy-3, c, fg, bg) 38 | } 39 | fg = termbox.ColorBlack 40 | bg = termbox.ColorGreen 41 | for i := 0; i <= len(t); i++ { 42 | for x := 0; x < 5*len(t); x++ { 43 | termbox.SetCell(ox+x, oy+i*2, '-', fg, bg) 44 | } 45 | for x := 0; x <= 2*len(t); x++ { 46 | if x%2 == 0 { 47 | termbox.SetCell(ox+i*5, oy+x, '+', fg, bg) 48 | } else { 49 | termbox.SetCell(ox+i*5, oy+x, '|', fg, bg) 50 | } 51 | } 52 | } 53 | fg = termbox.ColorYellow 54 | bg = termbox.ColorBlack 55 | for i := range t { 56 | for j := range t[i] { 57 | if t[i][j] > 0 { 58 | str := fmt.Sprint(t[i][j]) 59 | for n, char := range str { 60 | termbox.SetCell(ox+j*5+1+n, oy+i*2+1, char, fg, bg) 61 | } 62 | } 63 | } 64 | } 65 | return termbox.Flush() 66 | } 67 | -------------------------------------------------------------------------------- /box/transform.go: -------------------------------------------------------------------------------- 1 | // Package this file just provides another way to merger boxes. 2 | // I test this but I didn't use this because I finished write that fuck on 3 | // before this. I still haven't got the best . 4 | package box 5 | 6 | func (t *Box) Transpose() { 7 | tn := new(Box) 8 | for i, line := range t { 9 | for j, num := range line { 10 | tn[j][i] = num 11 | } 12 | } 13 | *t = *tn 14 | } 15 | func (t *Box) Right90() { 16 | tn := new(Box) 17 | for i, line := range t { 18 | for j, num := range line { 19 | tn[j][len(t)-i-1] = num 20 | } 21 | } 22 | *t = *tn 23 | } 24 | func (t *Box) Left90() { 25 | tn := new(Box) 26 | for i, line := range t { 27 | for j, num := range line { 28 | tn[len(line)-j-1][i] = num 29 | } 30 | } 31 | *t = *tn 32 | } 33 | func (t *Box) MirrorV() { 34 | tn := new(Box) 35 | for i, line := range t { 36 | for j, num := range line { 37 | tn[len(t)-i-1][j] = num 38 | } 39 | } 40 | *t = *tn 41 | } 42 | func (t *Box) MirrorH() { 43 | tn := new(Box) 44 | for i, line := range t { 45 | for j, num := range line { 46 | tn[i][len(line)-j-1] = num 47 | } 48 | } 49 | *t = *tn 50 | } 51 | -------------------------------------------------------------------------------- /box/win.go: -------------------------------------------------------------------------------- 1 | package box 2 | 3 | import ( 4 | "math/rand" 5 | ) 6 | 7 | type Status uint 8 | 9 | const ( 10 | Win Status = iota 11 | Lose 12 | Add 13 | Max = 2048 14 | ) 15 | 16 | func (t *Box) CheckWinAndAdd() Status { 17 | for _, x := range t { 18 | for _, y := range x { 19 | if y >= Max { 20 | return Win 21 | } 22 | } 23 | } 24 | i := rand.Intn(len(t)) 25 | j := rand.Intn(len(t)) 26 | for x := 0; x < len(t); x++ { 27 | for y := 0; y < len(t); y++ { 28 | if t[i%len(t)][j%len(t)] == 0 { 29 | t[i%len(t)][j%len(t)] = 2 << (rand.Uint32() % 2) 30 | return Add 31 | } 32 | j++ 33 | } 34 | i++ 35 | } 36 | return Lose 37 | } 38 | -------------------------------------------------------------------------------- /demo/demo.go: -------------------------------------------------------------------------------- 1 | package demo 2 | 3 | import ( 4 | "fmt" 5 | "github.com/nsf/termbox-go" 6 | "github.com/wangwenbin/2048-go/box" 7 | "math/rand" 8 | "time" 9 | ) 10 | 11 | func Go() { 12 | err := termbox.Init() 13 | if err != nil { 14 | panic(err) 15 | } 16 | defer termbox.Close() 17 | 18 | rand.Seed(time.Now().UnixNano()) 19 | 20 | A: 21 | b := box.Box{} 22 | box.Clear() 23 | for { 24 | st := b.CheckWinAndAdd() 25 | x, y := termbox.Size() 26 | b.Print(x/2-10, y/2-4) 27 | switch st { 28 | case box.Win: 29 | str := "Win!!" 30 | strl := len(str) 31 | box.CoverPrintStr(x/2-strl/2, y/2, str, termbox.ColorMagenta, termbox.ColorYellow) 32 | case box.Lose: 33 | str := "Lose!!" 34 | strl := len(str) 35 | box.CoverPrintStr(x/2-strl/2, y/2, str, termbox.ColorBlack, termbox.ColorRed) 36 | case box.Add: 37 | // b.Print(x/2-10, y/2-4) 38 | default: 39 | fmt.Print("Err") 40 | } 41 | //here get input, only keyarrow is pass,and return keyValue 42 | key := b.MergeAndReturnKey() 43 | if key == termbox.KeyEsc { 44 | return 45 | } 46 | if key == termbox.KeyEnter { 47 | goto A 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /img/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangwenbin/2048-go/15f757b296a3377371ff655ad93eb0e199fbef38/img/Screenshot.png --------------------------------------------------------------------------------