diff --git a/ai.go b/ai.go index 6cefefe..36ae97d 100644 --- a/ai.go +++ b/ai.go @@ -43,10 +43,15 @@ func (ai *Ai) ProcessQueue() { // GetBestQueue gets the best queue func (ai *Ai) GetBestQueue() { bestScore := -9999999 - bestQueue := make([]rune, 0, 0) - currentMino := *board.currentMino + bestQueue := []rune{'x'} + currentMino := board.currentMino + previewMino := board.previewMino rotations1 := 5 rotations2 := 5 + slides := 5 + if board.width > 10 { + slides = 3 + } switch currentMino.minoRotation[0][1][1] { case termbox.ColorCyan, termbox.ColorGreen, termbox.ColorRed: @@ -54,33 +59,33 @@ func (ai *Ai) GetBestQueue() { case termbox.ColorYellow: rotations1 = 1 } - switch board.previewMino.minoRotation[0][1][1] { + switch previewMino.minoRotation[0][1][1] { case termbox.ColorCyan, termbox.ColorGreen, termbox.ColorRed: rotations2 = 2 case termbox.ColorYellow: rotations2 = 1 } - for slide1 := 0; slide1 < 5; slide1++ { + for slide1 := 0; slide1 < slides; slide1++ { for move1 := board.width; move1 >= 0; move1-- { for rotate1 := 0; rotate1 < rotations1; rotate1++ { - queue, mino1 := board.getMovesforMino(rotate1, move1, slide1, ¤tMino, nil) + queue, mino1 := board.getMovesforMino(rotate1, move1, slide1, currentMino, nil) if mino1 == nil { continue } - for slide2 := 0; slide2 < 5; slide2++ { + for slide2 := 0; slide2 < slides; slide2++ { for move2 := board.width; move2 >= 0; move2-- { for rotate2 := 0; rotate2 < rotations2; rotate2++ { - _, mino2 := board.getMovesforMino(rotate2, move2, slide2, board.previewMino, mino1) + _, mino2 := board.getMovesforMino(rotate2, move2, slide2, previewMino, mino1) if mino2 == nil { continue } - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) - score := ai.getScoreFromBoardStats(fullLines, holes, bumpy) + fullLines, holes, bumpy, heightEnds := board.boardStatsWithMinos(mino1, mino2) + score := ai.getScoreFromBoardStats(fullLines, holes, bumpy, heightEnds, mino1.y, mino2.y) if score > bestScore { bestScore = score @@ -95,54 +100,53 @@ func (ai *Ai) GetBestQueue() { } } - if len(bestQueue) < 1 { - bestQueue = append(bestQueue, 'x') - } - ai.newQueue = &bestQueue } func (board *Board) getMovesforMino(rotate int, move int, slide int, mino1 *Mino, mino2 *Mino) ([]rune, *Mino) { - queue := make([]rune, 0, rotate+move+slide+1) + var i int + queue := make([]rune, 0, (rotate/2+1)+(move/2+1)+(slide/2+1)+1) mino := *mino1 + mino.MoveDown() + if rotate%2 == 0 { rotate /= 2 - for i := 0; i < rotate; i++ { + for i = 0; i < rotate; i++ { mino.RotateRight() - queue = append(queue, 'e') if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } + queue = append(queue, 'e') } } else { rotate = rotate/2 + 1 - for i := 0; i < rotate; i++ { + for i = 0; i < rotate; i++ { mino.RotateLeft() - queue = append(queue, 'q') if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } + queue = append(queue, 'q') } } if move%2 == 0 { move /= 2 - for i := 0; i < move; i++ { - mino.MoveLeft() - queue = append(queue, 'a') + for i = 0; i < move; i++ { + mino.MoveRight() if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } + queue = append(queue, 'd') } } else { move = move/2 + 1 - for i := 0; i < move; i++ { - mino.MoveRight() - queue = append(queue, 'd') + for i = 0; i < move; i++ { + mino.MoveLeft() if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } + queue = append(queue, 'a') } } for mino.ValidLocation(false) && (mino2 == nil || !mino2.minoOverlap(&mino)) { @@ -153,34 +157,35 @@ func (board *Board) getMovesforMino(rotate int, move int, slide int, mino1 *Mino if slide%2 == 0 { slide /= 2 - for i := 0; i < slide; i++ { + for i = 0; i < slide; i++ { mino.MoveLeft() - queue = append(queue, 'a') if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } + queue = append(queue, 'a') } } else { slide = slide/2 + 1 - for i := 0; i < slide; i++ { + for i = 0; i < slide; i++ { mino.MoveRight() - queue = append(queue, 'd') if !mino.ValidLocation(false) || (mino2 != nil && mino2.minoOverlap(&mino)) { return queue, nil } + queue = append(queue, 'd') } } if !mino.ValidLocation(true) { return queue, nil } - queue = append(queue, 'x') - return queue, &mino + + return append(queue, 'x'), &mino } -func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int, holes int, bumpy int) { +func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int, holes int, bumpy int, heightEnds int) { var i int var j int + // fullLines for j = 0; j < board.height; j++ { board.fullLinesY[j] = true @@ -196,47 +201,57 @@ func (board *Board) boardStatsWithMinos(mino1 *Mino, mino2 *Mino) (fullLines int } // holes and bumpy - indexLast := 0 + var foundLast int + var fullLinesFound int for i = 0; i < board.width; i++ { - index := board.height - indexOffset := 0 + found := board.height + fullLinesFound = 0 for j = 0; j < board.height; j++ { if board.fullLinesY[j] { - indexOffset++ + fullLinesFound++ } else { if board.colors[i][j] != blankColor || mino1.isMinoAtLocation(i, j) || mino2.isMinoAtLocation(i, j) { - index = j + found = j break } } } - if i != 0 { - diffrence := (index + fullLines - indexOffset) - indexLast + if i == 0 { + heightEnds = board.height - (found + fullLines - fullLinesFound) + } else { + diffrence := (found + fullLines - fullLinesFound) - foundLast if diffrence < 0 { diffrence = -diffrence } bumpy += diffrence - } - indexLast = index + fullLines - indexOffset + foundLast = found + fullLines - fullLinesFound - index++ - for k := index; k < board.height; k++ { - if board.colors[i][k] == blankColor && !mino1.isMinoAtLocation(i, k) && !mino2.isMinoAtLocation(i, k) { + for j++; j < board.height; j++ { + if board.colors[i][j] == blankColor && !mino1.isMinoAtLocation(i, j) && !mino2.isMinoAtLocation(i, j) { holes++ } } } + + heightEnds += board.height - foundLast + return } -func (ai *Ai) getScoreFromBoardStats(fullLines int, holes int, bumpy int) int { - score := 0 - if fullLines == 4 { +func (ai *Ai) getScoreFromBoardStats(fullLines int, holes int, bumpy int, heightEnds int, height1 int, height2 int) int { + score := 8 * heightEnds + if fullLines > 3 { score += 512 } - score -= 80 * holes - score -= 20 * bumpy + score -= 75 * holes + score -= 15 * bumpy + if height1 < 6 { + score -= 10 * (5 - height1) + } + if height2 < 6 { + score -= 10 * (5 - height2) + } return score } diff --git a/ai_test.go b/ai_test.go index f92305c..5959626 100644 --- a/ai_test.go +++ b/ai_test.go @@ -5,11 +5,12 @@ import ( ) type testAiStruct struct { - info string - minos []testMinoStruct - fullLines int - holes int - bumpy int + info string + minos []testMinoStruct + fullLines int + holes int + bumpy int + heightEnds int } func TestAI(t *testing.T) { @@ -21,32 +22,32 @@ func TestAI(t *testing.T) { {info: "fullLines 2x minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI - }, fullLines: 0, holes: 0, bumpy: 1}, + }, fullLines: 0, holes: 0, bumpy: 1, heightEnds: 1}, {info: "fullLines 2x2 minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 0, y: 17}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 17}, // minoI - }, fullLines: 0, holes: 0, bumpy: 2}, + }, fullLines: 0, holes: 0, bumpy: 2, heightEnds: 2}, {info: "fullLines 2x minoI minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI {minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO - }, fullLines: 1, holes: 0, bumpy: 1}, + }, fullLines: 1, holes: 0, bumpy: 1, heightEnds: 1}, {info: "fullLines 2x2 minoI minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 0, y: 17}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 17}, // minoI {minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO - }, fullLines: 2, holes: 0, bumpy: 0}, + }, fullLines: 2, holes: 0, bumpy: 0, heightEnds: 0}, {info: "fullLines 5x minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 2, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 4, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 6, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO - }, fullLines: 2, holes: 0, bumpy: 0}, + }, fullLines: 2, holes: 0, bumpy: 0, heightEnds: 0}, {info: "fullLines 4x4 minoI 2x minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI @@ -58,19 +59,19 @@ func TestAI(t *testing.T) { {minoRotation: minos.minoBag[0], x: 4, y: 15}, // minoI {minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 8, y: 16}, // minoO - }, fullLines: 4, holes: 0, bumpy: 0}, + }, fullLines: 4, holes: 0, bumpy: 0, heightEnds: 0}, {info: "holes 2x minoI minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 6, y: 18}, // minoI {minoRotation: minos.minoBag[3], x: 4, y: 17}, // minoO - }, fullLines: 0, holes: 2, bumpy: 4}, + }, fullLines: 0, holes: 2, bumpy: 4, heightEnds: 2}, {info: "holes 6x minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 4, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 8, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 2, y: 16}, // minoO {minoRotation: minos.minoBag[3], x: 6, y: 16}, // minoO - }, fullLines: 0, holes: 8, bumpy: 8}, + }, fullLines: 0, holes: 8, bumpy: 8, heightEnds: 4}, {info: "holes 4x minoT 2x minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[5], x: 0, y: 18}, // minoT {minoRotation: minos.minoBag[5], x: 7, y: 18}, // minoT @@ -78,12 +79,12 @@ func TestAI(t *testing.T) { {minoRotation: minos.minoBag[5], x: 7, y: 16}, // minoT {minoRotation: minos.minoBag[0], x: 2, y: 14}, // minoI {minoRotation: minos.minoBag[0], x: 6, y: 14}, // minoI - }, fullLines: 0, holes: 19, bumpy: 4}, + }, fullLines: 0, holes: 19, bumpy: 4, heightEnds: 6}, {info: "holes 3x minoZ", minos: []testMinoStruct{ {minoRotation: minos.minoBag[6], x: 0, y: 18}, // minoZ {minoRotation: minos.minoBag[6], x: 3, y: 18}, // minoZ {minoRotation: minos.minoBag[6], x: 6, y: 18}, // minoZ - }, fullLines: 0, holes: 3, bumpy: 6}, + }, fullLines: 0, holes: 3, bumpy: 6, heightEnds: 2}, {info: "holes 4x minoT 2x minoI 2x minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[5], x: 0, y: 18}, // minoT {minoRotation: minos.minoBag[5], x: 7, y: 18}, // minoT @@ -93,43 +94,43 @@ func TestAI(t *testing.T) { {minoRotation: minos.minoBag[3], x: 0, y: 14}, // minoO {minoRotation: minos.minoBag[0], x: 2, y: 14}, // minoI {minoRotation: minos.minoBag[0], x: 6, y: 14}, // minoI - }, fullLines: 1, holes: 9, bumpy: 16}, + }, fullLines: 1, holes: 9, bumpy: 16, heightEnds: 8}, {info: "bumpy 2x minoT - 1", minos: []testMinoStruct{ {minoRotation: minos.minoBag[5], x: 0, y: 18}, // minoT {minoRotation: minos.minoBag[5], x: 5, y: 18}, // minoT - }, fullLines: 0, holes: 0, bumpy: 7}, + }, fullLines: 0, holes: 0, bumpy: 7, heightEnds: 1}, {info: "bumpy 2x minoT - 2", minos: []testMinoStruct{ {minoRotation: minos.minoBag[5], x: 1, y: 18}, // minoT {minoRotation: minos.minoBag[5], x: 6, y: 18}, // minoT - }, fullLines: 0, holes: 0, bumpy: 8}, + }, fullLines: 0, holes: 0, bumpy: 8, heightEnds: 0}, {info: "bumpy 2x minoT - 3", minos: []testMinoStruct{ {minoRotation: minos.minoBag[5], x: 2, y: 18}, // minoT {minoRotation: minos.minoBag[5], x: 7, y: 18}, // minoT - }, fullLines: 0, holes: 0, bumpy: 7}, + }, fullLines: 0, holes: 0, bumpy: 7, heightEnds: 1}, {info: "bumpy 2x minoJ - 1", minos: []testMinoStruct{ {minoRotation: minos.minoBag[1], x: 0, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 5, y: 18}, // minoJ - }, fullLines: 0, holes: 0, bumpy: 6}, + }, fullLines: 0, holes: 0, bumpy: 6, heightEnds: 2}, {info: "bumpy 2x minoJ - 2", minos: []testMinoStruct{ {minoRotation: minos.minoBag[1], x: 1, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 6, y: 18}, // minoJ - }, fullLines: 0, holes: 0, bumpy: 8}, + }, fullLines: 0, holes: 0, bumpy: 8, heightEnds: 0}, {info: "bumpy 2x minoJ - 2", minos: []testMinoStruct{ {minoRotation: minos.minoBag[1], x: 2, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 7, y: 18}, // minoJ - }, fullLines: 0, holes: 0, bumpy: 7}, + }, fullLines: 0, holes: 0, bumpy: 7, heightEnds: 1}, {info: "bumpy 2x minoL - 1", minos: []testMinoStruct{ {minoRotation: minos.minoBag[2], x: 0, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 5, y: 18}, // minoL - }, fullLines: 0, holes: 0, bumpy: 7}, + }, fullLines: 0, holes: 0, bumpy: 7, heightEnds: 1}, {info: "bumpy 2x minoL - 2", minos: []testMinoStruct{ {minoRotation: minos.minoBag[2], x: 1, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 6, y: 18}, // minoL - }, fullLines: 0, holes: 0, bumpy: 8}, + }, fullLines: 0, holes: 0, bumpy: 8, heightEnds: 0}, {info: "bumpy 2x minoL - 3", minos: []testMinoStruct{ {minoRotation: minos.minoBag[2], x: 2, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 7, y: 18}, // minoL - }, fullLines: 0, holes: 0, bumpy: 6}, + }, fullLines: 0, holes: 0, bumpy: 6, heightEnds: 2}, } runAiTests(t, tests) @@ -146,14 +147,14 @@ func TestBigBoardAI(t *testing.T) { {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 8, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 12, y: 18}, // minoI - }, fullLines: 0, holes: 0, bumpy: 1}, + }, fullLines: 0, holes: 0, bumpy: 1, heightEnds: 1}, {info: "fullLines 5x minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 8, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 12, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 16, y: 18}, // minoI - }, fullLines: 1, holes: 0, bumpy: 0}, + }, fullLines: 1, holes: 0, bumpy: 0, heightEnds: 0}, {info: "fullLines 5x2 minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[0], x: 0, y: 18}, // minoI {minoRotation: minos.minoBag[0], x: 4, y: 18}, // minoI @@ -165,7 +166,7 @@ func TestBigBoardAI(t *testing.T) { {minoRotation: minos.minoBag[0], x: 8, y: 17}, // minoI {minoRotation: minos.minoBag[0], x: 12, y: 17}, // minoI {minoRotation: minos.minoBag[0], x: 16, y: 17}, // minoI - }, fullLines: 2, holes: 0, bumpy: 0}, + }, fullLines: 2, holes: 0, bumpy: 0, heightEnds: 0}, {info: "fullLines 9x minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 2, y: 18}, // minoO @@ -176,7 +177,7 @@ func TestBigBoardAI(t *testing.T) { {minoRotation: minos.minoBag[3], x: 12, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 14, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 16, y: 18}, // minoO - }, fullLines: 0, holes: 0, bumpy: 2}, + }, fullLines: 0, holes: 0, bumpy: 2, heightEnds: 2}, {info: "fullLines 10x minoO", minos: []testMinoStruct{ {minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 2, y: 18}, // minoO @@ -188,7 +189,7 @@ func TestBigBoardAI(t *testing.T) { {minoRotation: minos.minoBag[3], x: 14, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 16, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 18, y: 18}, // minoO - }, fullLines: 2, holes: 0, bumpy: 0}, + }, fullLines: 2, holes: 0, bumpy: 0, heightEnds: 0}, {info: "holes 3x minoO 3x minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[3], x: 0, y: 18}, // minoO {minoRotation: minos.minoBag[3], x: 6, y: 18}, // minoO @@ -196,14 +197,14 @@ func TestBigBoardAI(t *testing.T) { {minoRotation: minos.minoBag[0], x: 2, y: 16}, // minoI {minoRotation: minos.minoBag[0], x: 8, y: 16}, // minoI {minoRotation: minos.minoBag[0], x: 14, y: 16}, // minoI - }, fullLines: 0, holes: 24, bumpy: 8}, + }, fullLines: 0, holes: 24, bumpy: 8, heightEnds: 2}, {info: "holes 5x minoZ", minos: []testMinoStruct{ {minoRotation: minos.minoBag[6], x: 0, y: 18}, // minoZ {minoRotation: minos.minoBag[6], x: 4, y: 18}, // minoZ {minoRotation: minos.minoBag[6], x: 8, y: 18}, // minoZ {minoRotation: minos.minoBag[6], x: 12, y: 18}, // minoZ {minoRotation: minos.minoBag[6], x: 16, y: 18}, // minoZ - }, fullLines: 0, holes: 5, bumpy: 18}, + }, fullLines: 0, holes: 5, bumpy: 18, heightEnds: 2}, {info: "holes 6x minoT 2x minoO 5x minoI", minos: []testMinoStruct{ {minoRotation: minos.minoBag[5], x: 0, y: 18}, // minoT {minoRotation: minos.minoBag[5], x: 6, y: 18}, // minoT @@ -218,43 +219,79 @@ func TestBigBoardAI(t *testing.T) { {minoRotation: minos.minoBag[0], x: 8, y: 14}, // minoI {minoRotation: minos.minoBag[0], x: 12, y: 14}, // minoI {minoRotation: minos.minoBag[0], x: 16, y: 14}, // minoI - }, fullLines: 1, holes: 18, bumpy: 23}, + }, fullLines: 1, holes: 18, bumpy: 23, heightEnds: 5}, {info: "bumpy 4x minoJ - 1", minos: []testMinoStruct{ {minoRotation: minos.minoBag[1], x: 0, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 5, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 10, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 15, y: 18}, // minoJ - }, fullLines: 0, holes: 0, bumpy: 14}, + }, fullLines: 0, holes: 0, bumpy: 14, heightEnds: 2}, {info: "bumpy 4x minoJ - 2", minos: []testMinoStruct{ {minoRotation: minos.minoBag[1], x: 1, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 6, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 11, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 16, y: 18}, // minoJ - }, fullLines: 0, holes: 0, bumpy: 16}, + }, fullLines: 0, holes: 0, bumpy: 16, heightEnds: 0}, {info: "bumpy 4x minoJ - 3", minos: []testMinoStruct{ {minoRotation: minos.minoBag[1], x: 2, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 7, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 12, y: 18}, // minoJ {minoRotation: minos.minoBag[1], x: 17, y: 18}, // minoJ - }, fullLines: 0, holes: 0, bumpy: 15}, + }, fullLines: 0, holes: 0, bumpy: 15, heightEnds: 1}, {info: "bumpy 4x minoL - 1", minos: []testMinoStruct{ {minoRotation: minos.minoBag[2], x: 0, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 5, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 10, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 15, y: 18}, // minoL - }, fullLines: 0, holes: 0, bumpy: 15}, + }, fullLines: 0, holes: 0, bumpy: 15, heightEnds: 1}, {info: "bumpy 4x minoL - 2", minos: []testMinoStruct{ {minoRotation: minos.minoBag[2], x: 1, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 6, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 11, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 16, y: 18}, // minoL - }, fullLines: 0, holes: 0, bumpy: 16}, + }, fullLines: 0, holes: 0, bumpy: 16, heightEnds: 0}, {info: "bumpy 4x minoL - 3", minos: []testMinoStruct{ {minoRotation: minos.minoBag[2], x: 2, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 7, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 12, y: 18}, // minoL {minoRotation: minos.minoBag[2], x: 17, y: 18}, // minoL - }, fullLines: 0, holes: 0, bumpy: 14}, + }, fullLines: 0, holes: 0, bumpy: 14, heightEnds: 2}, + {info: "bumpy 4x minoL & 10x minoI", minos: []testMinoStruct{ + {minoRotation: minos.minoBag[2], x: 2, y: 18}, // minoL + {minoRotation: minos.minoBag[2], x: 7, y: 18}, // minoL + {minoRotation: minos.minoBag[2], x: 12, y: 18}, // minoL + {minoRotation: minos.minoBag[2], x: 17, y: 18}, // minoL + {minoRotation: minos.minoBag[0], x: 0, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 4, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 8, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 12, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 16, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 0, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 4, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 8, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 12, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 16, y: 15}, // minoI + }, fullLines: 2, holes: 0, bumpy: 14, heightEnds: 2}, + {info: "bumpy 8x minoL & 10x minoI", minos: []testMinoStruct{ + {minoRotation: minos.minoBag[2], x: 2, y: 18}, // minoL + {minoRotation: minos.minoBag[2], x: 7, y: 18}, // minoL + {minoRotation: minos.minoBag[2], x: 12, y: 18}, // minoL + {minoRotation: minos.minoBag[2], x: 17, y: 18}, // minoL + {minoRotation: minos.minoBag[0], x: 0, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 4, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 8, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 12, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 16, y: 16}, // minoI + {minoRotation: minos.minoBag[0], x: 0, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 4, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 8, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 12, y: 15}, // minoI + {minoRotation: minos.minoBag[0], x: 16, y: 15}, // minoI + {minoRotation: minos.minoBag[2], x: 2, y: 14}, // minoL + {minoRotation: minos.minoBag[2], x: 7, y: 14}, // minoL + {minoRotation: minos.minoBag[2], x: 12, y: 14}, // minoL + {minoRotation: minos.minoBag[2], x: 17, y: 14}, // minoL + }, fullLines: 2, holes: 8, bumpy: 28, heightEnds: 4}, } runAiTests(t, tests) @@ -282,7 +319,7 @@ func runAiTests(t *testing.T, tests []testAiStruct) { } } - fullLines, holes, bumpy := board.boardStatsWithMinos(mino1, mino2) + fullLines, holes, bumpy, heightEnds := board.boardStatsWithMinos(mino1, mino2) if fullLines != test.fullLines { mino1.SetOnBoard() @@ -311,6 +348,15 @@ func runAiTests(t *testing.T, tests []testAiStruct) { t.Errorf("AI bumpy - received: %v - expected: %v - info %v", bumpy, test.bumpy, test.info) continue } + if heightEnds != test.heightEnds { + mino1.SetOnBoard() + lines := board.getDebugBoardWithMino(mino2) + for i := 0; i < len(lines); i++ { + t.Log(lines[i]) + } + t.Errorf("AI heightEnds - received: %v - expected: %v - info %v", heightEnds, test.heightEnds, test.info) + continue + } } } diff --git a/boards.go b/boards.go index 6663120..f5c02bb 100644 --- a/boards.go +++ b/boards.go @@ -240,26 +240,26 @@ var boardsInternal = []byte(` "name":"10 x 20 checkerboard single", "mino":[ ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"] + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"] ], "rotation":[ - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ] }, @@ -408,46 +408,46 @@ var boardsInternal = []byte(` "name":"20 x 20 checkerboard single", "mino":[ ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"], ["b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z"], - ["b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"] + ["b","b","b","b","b","b","z","b","z","b","z","b","z","b","z","b","z","b","z","b"] ], "rotation":[ - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], - [0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], + [0,0,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ] }, diff --git a/mino.go b/mino.go index f88a7f9..c536533 100644 --- a/mino.go +++ b/mino.go @@ -100,10 +100,11 @@ func (mino *Mino) ValidLocation(mustBeOnBoard bool) bool { minoBlocks := mino.minoRotation[mino.rotation] for i := 0; i < mino.length; i++ { for j := 0; j < mino.length; j++ { - if minoBlocks[i][j] != blankColor { - if !board.ValidBlockLocation(mino.x+i, mino.y+j, mustBeOnBoard) { - return false - } + if minoBlocks[i][j] == blankColor { + continue + } + if !board.ValidBlockLocation(mino.x+i, mino.y+j, mustBeOnBoard) { + return false } } } @@ -148,10 +149,11 @@ func (mino *Mino) minoOverlap(mino1 *Mino) bool { minoBlocks := mino.minoRotation[mino.rotation] for i := 0; i < mino.length; i++ { for j := 0; j < mino.length; j++ { - if minoBlocks[i][j] != blankColor { - if mino1.isMinoAtLocation(mino.x+i, mino.y+j) { - return true - } + if minoBlocks[i][j] == blankColor { + continue + } + if mino1.isMinoAtLocation(mino.x+i, mino.y+j) { + return true } } } @@ -166,8 +168,7 @@ func (mino *Mino) isMinoAtLocation(x int, y int) bool { return false } - minoBlocks := mino.minoRotation[mino.rotation] - if minoBlocks[xIndex][yIndex] != blankColor { + if mino.minoRotation[mino.rotation][xIndex][yIndex] != blankColor { return true }