1 // jumpsaround.go - jumper game
    2 // (c) 2020 Alexander Kulbartsch
    3 // 
    4 // Slightly performace optimized version: valid jumpes checked bevore iteration.
    5 // added restricted multithreading
    6 
    7 package main
    8 
    9 import (
   10     "fmt"
   11     "sync"
   12     "sync/atomic"
   13 )
   14 
   15 const SIZEX = 6
   16 const SIZEY = 5
   17 const SPAWN = 2
   18 
   19 type boardt [SIZEX][SIZEY]int32
   20 var jump = [8][2]int32{{-1,-2}, {1,-2}, {-2,-1}, {2,-1}, {-2,1}, {2,1}, {-1,2}, {1,2}}
   21 var solutions int32  = 0
   22 var roundtrips int32 =  0
   23 
   24 var wg sync.WaitGroup
   25 var mutex sync.Mutex
   26 
   27 func main() {
   28     fmt.Println("Hello, Jumper!")
   29     var board boardt
   30     jumpto(board, 0, 0, 1)
   31     wg.Wait() // waiting for waitgroup processes
   32     fmt.Println("===== Solution #", solutions," (Roundtripps:", roundtrips, ") ====== ")    
   33     fmt.Println("I am done.")
   34 }
   35 
   36 
   37 func jumpto(board boardt, x, y, iter int32) {
   38 
   39     if iter == (SPAWN + 1) {
   40         defer wg.Done() 
   41     }
   42 
   43     // ok - store position
   44     board[x][y] = iter
   45     
   46     // finished ?
   47     if iter >= SIZEX*SIZEY {
   48 
   49         // check for jumper roundtrips
   50         round := false
   51         for _, d := range jump {
   52             nx := x + d[0]
   53             ny := y + d[1]
   54             // check if position is on the board
   55             if nx<0 || nx>(SIZEX-1) || ny<0 || ny>(SIZEY-1) { continue }
   56             // detect roundtrip
   57             if board[nx][ny] == 1 { round = true; atomic.AddInt32(&roundtrips,1); break } // True
   58         }
   59 
   60         atomic.AddInt32(&solutions, 1)
   61 
   62         printboard(board, round)
   63 
   64         //board[x][y] = 0  // it's local
   65         
   66         return
   67     }
   68     
   69     // try next jump
   70     for _, d := range jump {
   71         nx := x + d[0]
   72         ny := y + d[1]
   73 
   74         // check if position is on the board
   75         if nx<0 || nx>(SIZEX-1) || ny<0 || ny>(SIZEY-1) { continue }
   76 
   77         //  check if new field position is still empty
   78         if board[nx][ny] != 0 { continue } // True
   79 
   80         if iter == SPAWN {  // SPAWN = 2                                  // <<--
   81             wg.Add(1)
   82             go jumpto(board, nx, ny, iter + 1);                           // <<--
   83         } else { 
   84             jumpto(board, nx, ny, iter + 1);                              // <<--
   85         }
   86     }
   87     
   88     // this iteration is done
   89     board[x][y] = 0;
   90     
   91 }
   92 
   93 
   94 func printboard(board boardt, round bool) {
   95     mutex.Lock()                                                          // <<--
   96     if round == true { fmt.Println(" *** Roundtrip #", roundtrips, "*** ")
   97         fmt.Println("")
   98         for i := 0; i < SIZEY; i++ {
   99             for j := 0; j < SIZEX; j++ {
  100                 fmt.Printf("%2d:", board[j][i])
  101             }
  102             fmt.Println("")
  103         }
  104         fmt.Println("")
  105     }
  106     mutex.Unlock()                                                        // <<--
  107 }
  108 
  109 // EOF