Живко обнови решението на 22.01.2014 13:37 (преди над 4 години)
+package main
+
+import "sync"
+
+var (
+ mall [4][4]rune
+ log [][2][2]int
+)
+var (
+ playerLifes sync.WaitGroup
+ lockCond *sync.Cond
+ isMarkedMallCell [4][4]bool
+)
+var (
+ movesByPreference [][2]int = [][2]int{
+ {-1, -1},
+ {1, 1},
+ {1, -1},
+ {-1, 1}}
+ movesByPreferenceAndStatic [][2]int = make([][2]int, 5)
+)
+
+func isPlayerHere(cell rune) bool {
+ return cell == 'X'
+}
+
+func forEachPlayer(action func(rowID, columnID int)) {
+ for rowID, row := range mall {
+ for columnID, cellRune := range row {
+ if isPlayerHere(cellRune) {
+ action(rowID, columnID)
+ }
+ }
+ }
+}
+
+func getNumberOfplayers() (numberOfPlayers int) {
+ forEachPlayer(func(_, _ int) {
+ numberOfPlayers++
+ })
+ return
+}
+
+func setupWaitGroup(numberOfGoRutines int) {
+ playerLifes.Add(numberOfGoRutines)
+}
+
+func startPlayers() {
+ forEachPlayer(func(rowID, columnID int) {
+ go playerLive(rowID, columnID)
+ })
+}
+
+func newID(old, change int) int {
+ return (4 + old + change) % 4
+}
+
+func isNeighbourMoving(rowID, columnID int) bool {
+ isMarked := func(changeInRowID, changeInColumnID int) bool {
+ return isMarkedMallCell[newID(rowID, changeInRowID)][newID(columnID, changeInColumnID)] == true
+ }
+ return isMarked(0, 0) || isMarked(-1, -1) || isMarked(-1, 1) || isMarked(1, -1) || isMarked(1, 1)
+}
+
+func movePlayer(rowID, columnID *int) bool {
+ markCell := func(changeInRowID, changeInColumnID int) {
+ isMarkedMallCell[newID(*rowID, changeInRowID)][newID(*columnID, changeInColumnID)] = true
+ }
+ unmarkCell := func(changeInRowID, changeInColumnID, rowID, columnID int) {
+ isMarkedMallCell[newID(rowID, changeInRowID)][newID(columnID, changeInColumnID)] = false
+ }
+
+ lockCond.L.Lock()
+ for isNeighbourMoving(*rowID, *columnID) {
+ lockCond.Wait()
+ }
+ for _, moves := range movesByPreferenceAndStatic {
+ markCell(moves[0], moves[1])
+ }
+ defer func(rowID, columnID int) {
+ for _, moves := range movesByPreferenceAndStatic {
+ unmarkCell(moves[0], moves[1], rowID, columnID)
+ }
+ lockCond.L.Unlock()
+ lockCond.Broadcast()
+ }(*rowID, *columnID)
+
+ hasMoved := false
+ newRowID := *rowID
+ newColumnID := *columnID
+ for _, moves := range movesByPreference {
+ newRowID = newID(*rowID, moves[0])
+ newColumnID = newID(*columnID, moves[1])
+ if !isPlayerHere(mall[newRowID][newColumnID]) {
+ hasMoved = true
+ break
+ }
+ }
+
+ if hasMoved {
+ log = append(log, [2][2]int{[2]int{*rowID, *columnID},
+ [2]int{newRowID, newColumnID}})
+ mall[*rowID][*columnID] = '-'
+ mall[newRowID][newColumnID] = 'X'
+ *rowID = newRowID
+ *columnID = newColumnID
+ return true
+ } else {
+ log = append(log, [2][2]int{
+ {*rowID, *columnID},
+ {-2, -2}})
+ return false
+ }
+}
+
+func playerLive(rowID, columnID int) {
+ defer playerLifes.Done()
+
+ hasBlocked := false
+ for i := 0; i < 100; i++ {
+ if !movePlayer(&rowID, &columnID) {
+ hasBlocked = true
+ break
+ }
+ }
+ if !hasBlocked {
+ log = append(log, [2][2]int{
+ {rowID, columnID},
+ {-1, -1}})
+ }
+}
+
+func playMall(mall_input [4][4]rune) [][2][2]int {
+ mall = mall_input
+ log = make([][2][2]int, 0)
+ lockCond = sync.NewCond(new(sync.Mutex))
+ copy(movesByPreferenceAndStatic, movesByPreference)
+ movesByPreferenceAndStatic[4] = [2]int{0, 0}
+
+ numberOfPlayers := getNumberOfplayers()
+ if numberOfPlayers == 0 {
+ return [][2][2]int{{
+ {-1, -1},
+ {-1, -1}}}
+ } else {
+ setupWaitGroup(numberOfPlayers)
+ startPlayers()
+ playerLifes.Wait()
+ return log
+ }
+}
log
ти е глобална променлива, в която всички играчи могат да пишат един през друг. Очевиден race condition :)