| 562 | | } |
|---|
| 563 | | |
|---|
| 564 | | |
|---|
| 565 | | // ----------- class Pattern ----------------------------------------------- |
|---|
| 566 | | |
|---|
| 567 | | int Pattern::operator==(const &Pattern p) { |
|---|
| 568 | | if (sizeX != p.sizeX || sizeY != p.sizeY) return 0; |
|---|
| 569 | | if (anchors != p.anchors) return 0; // tupel? FIXME |
|---|
| 570 | | if (moveOne != p.moveOne) return 0; |
|---|
| 571 | | for(int i=0; i < sizeX; i++) |
|---|
| 572 | | if (initialData[i] != p.initialData[i]) return 0; |
|---|
| 573 | | if (contList != p.contList) return 0; // aufpassen ... FIXME |
|---|
| 574 | | return 1; |
|---|
| 575 | | } |
|---|
| 576 | | |
|---|
| 577 | | |
|---|
| 578 | | def Pattern::repr() { |
|---|
| 579 | | // """ final position!!! (FIXME?)""" |
|---|
| 580 | | return join(self.data, ''); |
|---|
| 581 | | } |
|---|
| 582 | | |
|---|
| 583 | | char Pattern::BW2XO(char c) { |
|---|
| 584 | | if (c == 'B') return 'X'; |
|---|
| 585 | | if (c == 'W') return 'O'; |
|---|
| 586 | | return c; |
|---|
| 587 | | } |
|---|
| 588 | | |
|---|
| 589 | | |
|---|
| 590 | | Pattern::Pattern(PyObject* anch, PyObject* initialDict, PyObject* contList, char mOne) { |
|---|
| 591 | | flip = 0; |
|---|
| 592 | | colorSwitch = 0; |
|---|
| 593 | | if (mOne=='B' || mOne=='X') moveOne = 'X' |
|---|
| 594 | | else moveOne = 'O'; |
|---|
| 595 | | if (moveOne == 'X') self.moveTwo = 'O'; |
|---|
| 596 | | else self.moveTwo = 'X'; |
|---|
| 597 | | |
|---|
| 598 | | anchors = anch; |
|---|
| 599 | | anchors.sort() |
|---|
| 600 | | |
|---|
| 601 | | l = initialDict.keys()[:] |
|---|
| 602 | | l.sort() |
|---|
| 603 | | |
|---|
| 604 | | start = l[0] |
|---|
| 605 | | end = l[len(l)-1] |
|---|
| 606 | | |
|---|
| 607 | | sizeX = end[0] - start[0] + 1 |
|---|
| 608 | | sizeY = end[1] - start[1] + 1 |
|---|
| 609 | | |
|---|
| 610 | | self.initialData = [] |
|---|
| 611 | | for i in range(self.sizeX): |
|---|
| 612 | | helpInitialData = [] |
|---|
| 613 | | for j in range(self.sizeY): |
|---|
| 614 | | helpInitialData.append(initialDict[(i+start[0], j+start[1])][0]) |
|---|
| 615 | | self.initialData.append(join(helpInitialData,'')) |
|---|
| 616 | | |
|---|
| 617 | | for x, y, co in contList: |
|---|
| 618 | | initialDict[(x,y)]=BW2XO(co) |
|---|
| 619 | | |
|---|
| 620 | | self.data = [] |
|---|
| 621 | | for i in range(self.sizeX): |
|---|
| 622 | | helpData = [] |
|---|
| 623 | | for j in range(self.sizeY): |
|---|
| 624 | | helpData.append(initialDict[(i+start[0], j+start[1])][0]) |
|---|
| 625 | | self.data.append(join(helpData,'')) |
|---|
| 626 | | |
|---|
| 627 | | self.contList = [(x-start[0], y-start[1], self.BW2XO(co)) for x, y, co in contList] |
|---|
| 628 | | |
|---|
| 629 | | self.bits = [] |
|---|
| 630 | | |
|---|
| 631 | | for i in range(2): |
|---|
| 632 | | for j in range(2): |
|---|
| 633 | | xBlocks = (self.sizeY+i+1)/2 |
|---|
| 634 | | yBlocks = (self.sizeX+j+1)/2 |
|---|
| 635 | | nextBlock = array('B', [yBlocks]) |
|---|
| 636 | | for k1 in range(yBlocks): |
|---|
| 637 | | nlist = [] |
|---|
| 638 | | |
|---|
| 639 | | for k2 in range(xBlocks): |
|---|
| 640 | | n = 0 |
|---|
| 641 | | for x in range(2): |
|---|
| 642 | | for y in range(2): |
|---|
| 643 | | indexX = k1 * 2 + y - j |
|---|
| 644 | | indexY = k2 * 2 + x - i |
|---|
| 645 | | if 0 <= indexX < self.sizeX and \ |
|---|
| 646 | | 0 <= indexY < self.sizeY: |
|---|
| 647 | | if self.data[indexX][indexY]=='X': |
|---|
| 648 | | n |= 1 << (2*(2*x+y)) |
|---|
| 649 | | elif self.data[indexX][indexY]=='O': |
|---|
| 650 | | n |= 1 << (2*(2*x+y)+1) |
|---|
| 651 | | nlist.append(n) |
|---|
| 652 | | |
|---|
| 653 | | start, end = 0, len(nlist) |
|---|
| 654 | | while start < end and not nlist[start]: start += 1 |
|---|
| 655 | | while end > start and not nlist[end-1]: end -= 1 |
|---|
| 656 | | |
|---|
| 657 | | nextBlock.append(start) |
|---|
| 658 | | nextBlock.append(end-start) |
|---|
| 659 | | for current in range(start, end): nextBlock.append(nlist[current]) |
|---|
| 660 | | |
|---|
| 661 | | self.bits.append(nextBlock) |
|---|
| 662 | | } |
|---|
| 663 | | |
|---|
| 664 | | |
|---|
| 665 | | flips = [] |
|---|
| 666 | | flips.append(lambda x,y, XX=18, YY=18: (x,y)) // FIXME: different boardsize |
|---|
| 667 | | flips.append(lambda x,y, XX=18, YY=18: (XX-x,y)) |
|---|
| 668 | | flips.append(lambda x,y, XX=18, YY=18: (x,YY-y)) |
|---|
| 669 | | flips.append(lambda x,y, XX=18, YY=18: (XX-x,YY-y)) |
|---|
| 670 | | flips.append(lambda x,y, XX=18, YY=18: (y,x)) |
|---|
| 671 | | flips.append(lambda x,y, XX=18, YY=18: (YY-y,x)) |
|---|
| 672 | | flips.append(lambda x,y, XX=18, YY=18: (y,XX-x)) |
|---|
| 673 | | flips.append(lambda x,y, XX=18, YY=18: (YY-y,XX-x)) |
|---|
| 674 | | |
|---|
| 675 | | |
|---|
| 676 | | int PatternInvFlip(i) { |
|---|
| 677 | | if (i == 5) return 6; |
|---|
| 678 | | if (i == 6) return 5; |
|---|
| 679 | | return i; |
|---|
| 680 | | } |
|---|
| 681 | | |
|---|
| 682 | | PatternList::PatternList(Pattern p, int fColor, int nextMove) { |
|---|
| 683 | | pattern = p; |
|---|
| 684 | | fixedColor = fColor; |
|---|
| 685 | | nextMove = nMove; |
|---|
| 686 | | |
|---|
| 687 | | data = patternList(); |
|---|
| 688 | | } |
|---|
| 689 | | |
|---|
| 690 | | |
|---|
| 691 | | char PatternList::invertColor(char co) { |
|---|
| 692 | | if (co == 'X') return 'O'; |
|---|
| 693 | | if (co == 'x') return 'o'; |
|---|
| 694 | | |
|---|
| 695 | | if (co == 'O') return 'X'; |
|---|
| 696 | | if (co == 'o') return 'x'; |
|---|
| 697 | | |
|---|
| 698 | | return co; |
|---|
| 699 | | } |
|---|
| 700 | | |
|---|
| 701 | | vector<Pattern> PatternList::patternList() { |
|---|
| 702 | | |
|---|
| 703 | | l = [] |
|---|
| 704 | | lCS = [] |
|---|
| 705 | | symmetries = [] |
|---|
| 706 | | |
|---|
| 707 | | special = -1 |
|---|
| 708 | | |
|---|
| 709 | | for ii in range(len(Pattern.flips)): |
|---|
| 710 | | f = Pattern.flips[ii] |
|---|
| 711 | | finv = Pattern.flips[PatternInvFlip(ii)] |
|---|
| 712 | | |
|---|
| 713 | | newA = [] |
|---|
| 714 | | |
|---|
| 715 | | a = [(self.pattern.anchors[0][0],self.pattern.anchors[0][1]), |
|---|
| 716 | | (self.pattern.anchors[1][0],self.pattern.anchors[0][1]), |
|---|
| 717 | | (self.pattern.anchors[1][0],self.pattern.anchors[1][1]), |
|---|
| 718 | | (self.pattern.anchors[0][0],self.pattern.anchors[1][1])] |
|---|
| 719 | | |
|---|
| 720 | | for anchor in a: |
|---|
| 721 | | extr = [ f(anchor[0], anchor[1]), |
|---|
| 722 | | f(anchor[0]+self.pattern.sizeX-1, anchor[1]), |
|---|
| 723 | | f(anchor[0], anchor[1]+self.pattern.sizeY-1), |
|---|
| 724 | | f(anchor[0]+self.pattern.sizeX-1, anchor[1]+self.pattern.sizeY-1) ] |
|---|
| 725 | | |
|---|
| 726 | | extr.sort() |
|---|
| 727 | | newA.append(extr[0]) |
|---|
| 728 | | |
|---|
| 729 | | newA.sort() |
|---|
| 730 | | newAnchors = [newA[0], newA[3]] |
|---|
| 731 | | |
|---|
| 732 | | newPd = {} |
|---|
| 733 | | |
|---|
| 734 | | for i in range(self.pattern.sizeX): |
|---|
| 735 | | for j in range(self.pattern.sizeY): |
|---|
| 736 | | newPd[f(i,j)] = self.pattern.initialData[i][j] |
|---|
| 737 | | |
|---|
| 738 | | newContList = [f(i,j)+(co,) for i,j,co in self.pattern.contList] |
|---|
| 739 | | pNew = Pattern(newAnchors, newPd, newContList, self.pattern.moveOne) |
|---|
| 740 | | pNew.flip = ii |
|---|
| 741 | | |
|---|
| 742 | | if not pNew in l: l.append(pNew) |
|---|
| 743 | | if pNew == self.pattern: symmetries.append((ii,0)) |
|---|
| 744 | | |
|---|
| 745 | | if self.nextMove or not self.fixedColor: |
|---|
| 746 | | newPd1 = {} |
|---|
| 747 | | for i in range(self.pattern.sizeX): |
|---|
| 748 | | for j in range(self.pattern.sizeY): |
|---|
| 749 | | newPd1[f(i,j)] = self.invertColor(self.pattern.initialData[i][j]) |
|---|
| 750 | | |
|---|
| 751 | | newContList1 = [f(i,j)+(self.invertColor(co),) for i,j,co in self.pattern.contList] |
|---|
| 752 | | pNew1 = Pattern(newAnchors, newPd1, newContList1, self.pattern.moveTwo) |
|---|
| 753 | | pNew1.flip = ii |
|---|
| 754 | | pNew1.colorSwitch = 1 |
|---|
| 755 | | |
|---|
| 756 | | if not self.fixedColor and not pNew1 in lCS: lCS.append(pNew1) |
|---|
| 757 | | if pNew1 == self.pattern: |
|---|
| 758 | | if not self.fixedColor: symmetries.append((ii,1)) |
|---|
| 759 | | if self.nextMove: special = ii |
|---|
| 760 | | |
|---|
| 761 | | for p in lCS: |
|---|
| 762 | | if not p in l: l.append(p) |
|---|
| 763 | | |
|---|
| 764 | | symm = {} |
|---|
| 765 | | for i in range(self.pattern.sizeX): |
|---|
| 766 | | for j in range(self.pattern.sizeY): |
|---|
| 767 | | symm[(i,j)] = ((i,j),0) |
|---|
| 768 | | |
|---|
| 769 | | for s, c in symmetries: |
|---|
| 770 | | symm1 = {} |
|---|
| 771 | | for i in range(self.pattern.sizeX): |
|---|
| 772 | | for j in range(self.pattern.sizeY): |
|---|
| 773 | | if (i,j) != Pattern.flips[s](i,j,self.pattern.sizeX-1,self.pattern.sizeY-1) \ |
|---|
| 774 | | and not symm1.has_key(Pattern.flips[s](i,j,self.pattern.sizeX-1,self.pattern.sizeY-1)): |
|---|
| 775 | | symm1[(i,j)] = (Pattern.flips[s](i,j,self.pattern.sizeX-1,self.pattern.sizeY-1), c) |
|---|
| 776 | | |
|---|
| 777 | | for k in symm.keys(): |
|---|
| 778 | | if symm1.has_key(symm[k][0]): |
|---|
| 779 | | if (symm1[symm[k][0]][1] or symm[k][1]) and \ |
|---|
| 780 | | not (symm1[symm[k][0]][1] and symm[k][1]): |
|---|
| 781 | | cs = 1 |
|---|
| 782 | | else: cs = 0 |
|---|
| 783 | | symm[k] = symm1[symm[k][0]][0], cs |
|---|
| 784 | | |
|---|
| 785 | | if special == -1: |
|---|
| 786 | | symm[-1] = -1 |
|---|
| 787 | | else: |
|---|
| 788 | | symm[-1] = PatternInvFlip(special) |
|---|
| 789 | | |
|---|
| 790 | | self.symmetries = symm |
|---|
| 791 | | return l |
|---|
| 792 | | } |
|---|
| 793 | | |
|---|
| 794 | | |
|---|
| 795 | | Pattern PatternList::get(int i) { |
|---|
| 796 | | return data[i]; |
|---|
| 797 | | } |
|---|
| 798 | | |
|---|
| 799 | | |
|---|
| 800 | | int PatternList::size() { |
|---|
| 801 | | return data.size(); |
|---|
| 802 | | } |
|---|
| 803 | | |
|---|
| 804 | | |
|---|
| 805 | | PatternList::updateContinuations(index, x, y, co, Xint, Yint, |
|---|
| 806 | | foundWhere, counter, |
|---|
| 807 | | continuations, contLabels, contLabelsIndex, |
|---|
| 808 | | winner) { |
|---|
| 809 | | |
|---|
| 810 | | xx, yy = Pattern.flips[PatternInvFlip(self.data[index].flip)](x, y) |
|---|
| 811 | | |
|---|
| 812 | | XX1, YY1 = Pattern.flips[PatternInvFlip(self.data[index].flip)](Xint[0], Yint[0]) |
|---|
| 813 | | XX2, YY2 = Pattern.flips[PatternInvFlip(self.data[index].flip)](Xint[1]-1, Yint[1]-1) |
|---|
| 814 | | XX = min(XX1, XX2) |
|---|
| 815 | | YY = min(YY1, YY2) |
|---|
| 816 | | |
|---|
| 817 | | xx -= XX |
|---|
| 818 | | yy -= YY |
|---|
| 819 | | |
|---|
| 820 | | if (self.data[index].colorSwitch and co == 'X') or \ |
|---|
| 821 | | (not self.data[index].colorSwitch and co == 'O'): |
|---|
| 822 | | cc = 'B' |
|---|
| 823 | | else: cc = 'W' |
|---|
| 824 | | |
|---|
| 825 | | (xx, yy), cSymm = self.symmetries[(xx,yy)] |
|---|
| 826 | | |
|---|
| 827 | | if (cc == 'B' and not cSymm) or (cc=='W' and cSymm): cc = 'B' |
|---|
| 828 | | else: cc = 'W' |
|---|
| 829 | | |
|---|
| 830 | | if self.nextMove: |
|---|
| 831 | | if ((self.nextMove == 2 and cc == 'B') \ |
|---|
| 832 | | or (self.nextMove == 1 and cc == 'W')): |
|---|
| 833 | | if self.symmetries[-1] != -1 and not self.fixedColor: |
|---|
| 834 | | |
|---|
| 835 | | if cc == 'B': cc='W' |
|---|
| 836 | | else: cc = 'B' |
|---|
| 837 | | |
|---|
| 838 | | xx += XX |
|---|
| 839 | | yy += YY |
|---|
| 840 | | |
|---|
| 841 | | xx, yy = Pattern.flips[self.symmetries[-1]](xx, yy) |
|---|
| 842 | | |
|---|
| 843 | | XX1, YY1 = Pattern.flips[self.symmetries[-1]](XX1, YY1) |
|---|
| 844 | | XX2, YY2 = Pattern.flips[self.symmetries[-1]](XX2, YY2) |
|---|
| 845 | | |
|---|
| 846 | | XX = min(XX1, XX2) |
|---|
| 847 | | YY = min(YY1, YY2) |
|---|
| 848 | | |
|---|
| 849 | | xx -= XX |
|---|
| 850 | | yy -= YY |
|---|
| 851 | | |
|---|
| 852 | | (xx1, yy1), cSymm1 = self.symmetries[(xx,yy)] |
|---|
| 853 | | if not cSymm1: |
|---|
| 854 | | xx, yy = xx1, yy1 |
|---|
| 855 | | |
|---|
| 856 | | colorSwitch = 1-cSymm |
|---|
| 857 | | if colorSwitch: numOfSwitched += 1 |
|---|
| 858 | | else: |
|---|
| 859 | | return 0,0,0,0 |
|---|
| 860 | | else: |
|---|
| 861 | | colorSwitch = cSymm |
|---|
| 862 | | if colorSwitch: numOfSwitched += 1 |
|---|
| 863 | | else: |
|---|
| 864 | | colorSwitch = cSymm |
|---|
| 865 | | |
|---|
| 866 | | if continuations.has_key((xx, yy)): |
|---|
| 867 | | continuations[(xx,yy)][cc] = continuations[(xx,yy)][cc]+1 |
|---|
| 868 | | else: |
|---|
| 869 | | if contLabelsIndex >= len(contLabels): text = '?' |
|---|
| 870 | | else: |
|---|
| 871 | | text = contLabels[contLabelsIndex] |
|---|
| 872 | | contLabelsIndex += 1 |
|---|
| 873 | | if cc == 'B': |
|---|
| 874 | | continuations[(xx,yy)] = {'B':1, 'W':0, |
|---|
| 875 | | 'tB':0, 'tW':0, |
|---|
| 876 | | 'wB':0,'lB':0,'wW':0,'lW':0, |
|---|
| 877 | | 'N': text} |
|---|
| 878 | | else: |
|---|
| 879 | | continuations[(xx,yy)] = {'B':0, 'W':1, 'tB':0, 'tW':0, 'wB':0, 'lB':0, |
|---|
| 880 | | 'wW':0, 'lW':0, 'N': text} |
|---|
| 881 | | |
|---|
| 882 | | if not foundWhere in [counter, counter+1]: |
|---|
| 883 | | continuations[(xx,yy)]['t'+cc] += 1 |
|---|
| 884 | | |
|---|
| 885 | | if winner == 'B': |
|---|
| 886 | | if not (self.data[index].colorSwitch or colorSwitch): |
|---|
| 887 | | continuations[(xx,yy)]['w'+cc] += 1 |
|---|
| 888 | | else: |
|---|
| 889 | | continuations[(xx,yy)]['l'+cc] += 1 |
|---|
| 890 | | elif winner == 'W': |
|---|
| 891 | | if not (self.data[index].colorSwitch or colorSwitch): |
|---|
| 892 | | continuations[(xx,yy)]['l'+cc] += 1 |
|---|
| 893 | | else: |
|---|
| 894 | | continuations[(xx,yy)]['w'+cc] += 1 |
|---|
| 895 | | |
|---|
| 896 | | return 1, continuations[(xx,yy)]['N'], contLabelsIndex, (self.data[index].colorSwitch or colorSwitch) |
|---|
| 897 | | |
|---|