代码拉取完成,页面将自动刷新
同步操作将从 xiaochi/gogo 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
package gogo
import (
"bufio"
"errors"
"fmt"
"log"
"os"
"regexp"
"sort"
"strconv"
"strings"
"sync"
"time"
)
type XY struct {
X, Y int
}
func NewXY(x, y int) XY {
return XY{x, y}
}
type UB struct {
Uid, Bid int
}
func NewUB(u, b int) UB {
return UB{u, b}
}
type Gozi struct {
X int `json:"x"`
Y int `json:"y"`
Uid int `json:"uid"`
}
type DebugInfoXY struct {
X int
Y int
Bid int
Uid int
}
func NewDebugInfoXY(xy XY, ub UB) DebugInfoXY {
return DebugInfoXY{xy.X, xy.Y, ub.Bid, ub.Uid}
}
type DebugInfoBlock struct {
Bid int
XYs [][]int
Qi int
}
type DebugInfo struct {
XYs []DebugInfoXY
Blocks []DebugInfoBlock
}
type block struct {
Qi int
XYs Set[XY]
}
func newBlock() block {
return block{0, NewSet[XY]()}
}
var mapXYUB = map[XY]UB{}
var mapBXYsQ = map[int]block{}
var curBid = 0
var mutex sync.RWMutex
var fileLogName = "gogo.journal"
var fileLog *log.Logger
func DebugState() {
fmt.Println("===")
fmt.Printf("curBid: %d\n", curBid)
fmt.Printf("mapXYU\tx,y\t| uid\t| bid\n")
for xy, ub := range mapXYUB {
fmt.Printf("\t%d,%d\t| %d\t| %d\n", xy.X, xy.Y, ub.Uid, ub.Bid)
}
fmt.Printf("mapBQ\tbid\t| qi\t| [x,y]\n")
for bid, b := range mapBXYsQ {
fmt.Printf("\t%d\t| %d\t| ", bid, b.Qi)
for xy := range b.XYs {
fmt.Printf("%d,%d\t", xy.X, xy.Y)
}
fmt.Printf("\n")
}
// fmt.Println("===")
}
func GetDebugInfo() DebugInfo {
our := []DebugInfoXY{}
for xy, ub := range mapXYUB {
our = append(our, NewDebugInfoXY(xy, ub))
}
bs := []DebugInfoBlock{}
for b, bk := range mapBXYsQ {
a := [][]int{}
for xy := range bk.XYs {
a = append(a, []int{xy.X, xy.Y})
}
bs = append(bs, DebugInfoBlock{b, a, bk.Qi})
}
return DebugInfo{our, bs}
}
func nextBid() int {
curBid++
return curBid
}
func findBid(bid int) (xys Set[XY], ok bool) {
b, ok := mapBXYsQ[bid]
return b.XYs, ok
}
func findNeis(xy XY) []XY {
x, y := xy.X, xy.Y
return []XY{
{x - 1, y},
{x + 1, y},
{x, y - 1},
{x, y + 1},
}
}
func neisKinds(neis []XY, uid int) (empty Set[XY], our Set[XY], other Set[XY]) {
empty, our, other = NewSet[XY](), NewSet[XY](), NewSet[XY]()
for _, xy := range neis {
ub, ok := mapXYUB[xy]
if !ok {
empty.Add(xy)
} else if ub.Uid == uid {
our.Add(xy)
} else {
other.Add(xy)
}
}
return
}
func ziBids(xys Set[XY]) (bids Set[int]) {
m := NewSet[int]()
for xy := range xys {
ub, ok := mapXYUB[xy]
if ok {
m.Add(ub.Bid)
}
}
return m
}
func dryInsert(x, y int, uid int) int {
xy := NewXY(x, y)
ourbid := nextBid()
ub := NewUB(uid, ourbid)
mapXYUB[xy] = ub
return ourbid
}
func Insert(x, y int, uid int) error {
mutex.Lock()
defer mutex.Unlock()
err := insert0(x, y, uid)
if err != nil {
return err
}
fileLog.Printf("%d,%d %d\n", x, y, uid)
return nil
}
func setBid(xy XY, bid int) {
ub := mapXYUB[xy]
ub.Bid = bid
mapXYUB[xy] = ub
}
func setUid(xy XY, uid int) {
ub := mapXYUB[xy]
ub.Uid = uid
mapXYUB[xy] = ub
}
func appendXY(bid int, xy XY) Set[XY] {
b := mapBXYsQ[bid]
b.XYs[xy] = true
mapBXYsQ[bid] = b
return b.XYs
}
func setXYs(bid int, xys Set[XY]) Set[XY] {
b := mapBXYsQ[bid]
b.XYs = xys
mapBXYsQ[bid] = b
return xys
}
func setQi(bid int, qi int) int {
b := mapBXYsQ[bid]
b.Qi = qi
mapBXYsQ[bid] = b
return qi
}
func setQiMinus(bid int) int {
return setQi(bid, mapBXYsQ[bid].Qi-1)
}
func insert0(x, y int, uid int) error {
xy := NewXY(x, y)
if _, ok := mapXYUB[xy]; ok {
return errors.New("x y already exists")
}
ourbid := dryInsert(x, y, uid)
// === step 1 ===
// xy就是我们刚刚下的子的坐标
// 这一步是找到这个子的四个邻居(不论是己方,敌方,还是空)
neis := findNeis(xy)
// 这一步是将邻居分分类。
// 空,己方,敌方
empty, our, other := neisKinds(neis, uid)
// 己方棋子分别属于那几个块呢?由下面这个函数回答
bids := ziBids(our)
// 如果有一个或者多于一个的块
if len(bids) > 0 {
// 那么就把这些块的bid统一成一个
ourbid = updateBids(xy, bids)
// 当然别忘记我们刚刚下的子
setBid(xy, ourbid)
// maybe we should count qi here
}
// === step 2 ===
if _, ok := mapBXYsQ[ourbid]; !ok {
mapBXYsQ[ourbid] = newBlock()
}
xys := appendXY(ourbid, xy)
setQi(ourbid, countQi(xys))
// determine will do step 2
if !allUsAlive(len(empty), len(other)) {
toDel := NewSet[int]()
bids = ziBids(other)
for bid := range bids {
qi := setQiMinus(bid)
if qi == 0 {
toDel.Add(bid)
}
}
if len(toDel) > 0 {
reCalBids := needReCal(toDel)
for bid := range toDel {
delBlock(bid)
}
reCalBlocks(reCalBids)
}
// === step 3 ===
qi := reCountQi(ourbid)
if len(toDel) == 0 {
if qi == 0 {
reCalBids := needReCal(NewSet(ourbid))
delBlock(ourbid)
reCalBlocks(reCalBids)
}
}
}
return nil
}
func reCountQi(bid int) int {
return setQi(bid, countQi(mapBXYsQ[bid].XYs))
}
func reCalBlocks(bids Set[int]) {
for bid := range bids {
reCountQi(bid)
}
}
// 需要重新计算
// 被提子周围的棋子所在的块需要重新计算
func needReCal(toDel Set[int]) Set[int] {
reCal := NewSet[int]() // bids
for bid := range toDel {
our, _ := findBid(bid)
allNeis := NewSet[XY]()
for xy := range our {
allNeis.Add(findNeis(xy)...)
}
a := ziBids(allNeis)
reCal.Union(a)
}
return reCal.Sub(toDel)
}
func delBlock(bid int) {
xys, _ := findBid(bid)
for xy := range xys {
delete(mapXYUB, xy)
}
delete(mapBXYsQ, bid)
}
func allUsAlive(emptyN, otherN int) bool {
return emptyN > 0 && otherN == 0
}
func countQi(xys Set[XY]) (n int) {
m := map[XY]bool{}
for xy := range xys {
delete(m, xy)
z := findNeis(xy)
for _, k := range z {
m[k] = true
}
}
for xy := range m {
if _, ok := mapXYUB[xy]; !ok {
n += 1
}
}
return n
}
func minInt(ints Set[int]) int {
xs := ints.Slice()
sort.Ints(xs)
return xs[0]
}
// 合成一个块
func updateBids(xy XY, bids Set[int]) (bid int) {
bid = minInt(bids)
a := NewSet(xy)
for b := range bids {
setBidForAll(mapBXYsQ[b].XYs, bid)
a.Union(mapBXYsQ[b].XYs)
delete(mapBXYsQ, b)
}
setXYs(bid, a)
return
}
func setBidForAll(xys Set[XY], bid int) {
for xy := range xys {
setBid(xy, bid)
}
}
func GetRect(x1, y1, x2, y2 int) (a []Gozi) {
a = []Gozi{}
mutex.Lock()
defer mutex.Unlock()
for i := x1; i <= x2; i++ {
for j := y1; j <= y2; j++ {
if ub, ok := mapXYUB[NewXY(i, j)]; ok {
a = append(a, Gozi{(i), (j), ub.Uid})
}
}
}
return
}
func Init(persist bool, lname string) *os.File {
mapXYUB = map[XY]UB{}
mapBXYsQ = map[int]block{}
fileLogName = lname
if persist {
doPersisit()
}
f, err := os.OpenFile(fileLogName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
fileLog = log.New(f, "", log.LstdFlags)
return f
}
var reInsert = regexp.MustCompile(`^INSERT INTO ZI\b`)
var reValue = regexp.MustCompile(`\bVALUES\s(.+);`)
func LoadFromSql(fname string) {
f, err := os.Open(fname)
if err != nil {
log.Fatal(err)
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
line := s.Bytes()
if reInsert.Match(line) {
log.Printf("%s\n", line)
m := reValue.FindSubmatch(line)
// log.Printf("%s\n", m)
words := strings.Split(string(m[1]), " ")
a := []int{}
for _, e := range words {
d, err := strconv.Atoi(strings.Trim(e, "(,)"))
if err != nil {
log.Fatal(err)
}
a = append(a, d)
}
// log.Printf("insert %v\n", a)
Insert((a[1]), (a[2]), a[4])
}
}
}
func doPersisit() {
f, err := os.Open(fileLogName)
if err != nil {
return
}
defer f.Close()
t := time.Now()
s := bufio.NewScanner(f)
n := 0
for s.Scan() {
line := s.Text()
a := strings.Split(line, " ")
xy, uid := a[2], a[3]
x, y := sep2int(xy)
u := mustAtoi(uid)
insert0(x, y, u)
n++
}
d := time.Now().Sub(t)
log.Printf("%d loaded in %s\n", n, d.String())
}
func sep2int(s string) (int, int) {
a := strings.Split(s, ",")
return mustAtoi(a[0]), mustAtoi(a[1])
}
func mustAtoi(s string) int {
n, err := strconv.Atoi(s)
if err != nil {
log.Fatal(err)
}
return n
}
// todo func snapshot
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。