দীর্ঘতম অ-পুনরাবৃত্তি গেম-অফ-লাইফ সিকোয়েন্স


16

একটি ধনাত্মক পূর্ণসংখ্যার এন দেওয়া হয়েছে, একটি এন এক্স এন-গ্রিডের প্রারম্ভিক প্যাটার্নটি নির্ধারণ করুন যা গেম অফ লাইফ-বিধিগুলির অধীনে দীর্ঘতম অ-পুনরাবৃত্তি ক্রম দেয় এবং একটি টরাস এ খেলে একটি নির্দিষ্ট প্যাটার্ন (দৈর্ঘ্য 1 চক্র) দিয়ে শেষ হয়।

লক্ষ্যটি সংক্ষিপ্ততম প্রোগ্রাম নয়, তবে দ্রুত।

যেহেতু পৃথিবী সীমাবদ্ধ, আপনি অবশেষে একটি লুপে শেষ করবেন, এভাবে ইতিমধ্যে পরিদর্শন করা রাষ্ট্রটির পুনরাবৃত্তি করুন। যদি এই লুপটির মেয়াদ 1 থাকে তবে প্রারম্ভিক প্যাটার্নটি বৈধ প্রার্থী।

আউটপুট: প্রারম্ভিক প্যাটার্ন এবং অনুক্রমের অনন্য রাজ্যের মোট সংখ্যা (প্রারম্ভিক প্যাটার্ন সহ)।

এখন, 1x1-টরাসটি বিশেষ, যেহেতু কোনও সেল নিজের কাছে প্রতিবেশী হিসাবে বিবেচিত হয় বা নাও হতে পারে, তবে বাস্তবে কোনও সমস্যা নেই, একক জীবিত কোষ উভয় ক্ষেত্রেই কেবল মারা যাবে (অতিরিক্ত জনাকীর্ণ বা নিঃসঙ্গতার কারণে)। সুতরাং, ইনপুট 1 দৈর্ঘ্য 2 এর ক্রম উত্পাদন করে, ক্রমটি এককক্ষের জীবন্ত থাকে, তারপরে চিরকালের জন্য মৃত।

এই প্রশ্নের অনুপ্রেরণা হ'ল এটি ব্যস্ত বিভার ফাংশনের একটি অ্যানালগ, তবে স্পষ্টতই কম জটিল, কারণ আমাদের স্মৃতির উপর একটি আবদ্ধ। এটি OEIS এ অন্তর্ভুক্ত করার জন্য একটি দুর্দান্ত ক্রম হবে।

এন = 3 এর জন্য, সিকোয়েন্স দৈর্ঘ্য 3, বাম দিকে যে কোনও প্যাটার্ন সম্পূর্ণ কালো 3x3-স্কোয়ারে পৌঁছে এবং তারপরে মারা যায়। (1 টি চক্রের অংশযুক্ত সমস্ত নিদর্শনগুলি সরানো হয়েছে)।

রাজ্যের গ্রাফ


1
আহ, ঠিক আছে। সেরা কোডটি হ'ল 2 ঘন্টা বলুন যে বৃহত্তম এন এর জন্য সিকোয়েন্স দৈর্ঘ্য গণনা করতে পরিচালিত করে। সুস্পষ্ট জটিলতা 2 ^ (N ^ 2), সুতরাং যদি এটির উন্নতি করা সম্ভব হয় তবে এটি দুর্দান্ত।
আলেকজান্ডারসন

1
তুচ্ছ আকারে প্রতিটি প্যাটার্ন 8N ^ 2 নিদর্শনগুলির একটি আইসোমর্ফিিজম শ্রেণির অংশ, সুতরাং যদি ক্যানোনিকালাইজেশনের একটি দ্রুত উপায় থাকে তবে এটি একটি মাঝারি উত্সাহ দেয়।
পিটার টেলর

1
এই ক্রমটি কি ওইআইএস-এ যুক্ত হয়েছে?
mbomb007

1
আমি যে সম্পর্কে সচেতন তা নয়, এটি সেখানে দেখে খুশি হবেন।
আলেকজান্দারসন

1
আমি এই ক্রমটি (2, 2, 3, 10, 52, 91) A294241 হিসাবে OEIS এ জমা দিয়েছি
পিটার কেজি

উত্তর:


13

সি ++ এন = 6 পর্যন্ত

3x3 answer 3: 111 000 000                                                                                        
4x4 answer 10: 1110 0010 1100 0000                                                                               
5x5 answer 52: 11010 10000 11011 10100 00000                                                                     
6x6 answer 91: 100011 010100 110011 110100 101000 100000                                                         

এই কৌশলটি দ্রুত পরবর্তী রাষ্ট্রীয় কার্যক্রমে কেন্দ্র করে। প্রতিটি বোর্ড N ^ 2 বিটের বিটমাস্ক হিসাবে উপস্থাপিত হয় এবং বিট-টুইডলি ট্রিকস একই সাথে সমস্ত কক্ষের জন্য পরবর্তী অবস্থার গণনা করতে ব্যবহৃত হয়। এন <= 8 এর জন্য nextপ্রায় 200 100 সমাবেশ নির্দেশনাগুলি সঙ্কলন করে তারপরে আমরা কেবলমাত্র সমস্ত-রাজ্যগুলির-তারা-পুনরাবৃত্তি হওয়া পর্যন্ত স্ট্যান্ডার্ড চেষ্টা করি এবং দীর্ঘতমটি চয়ন করি।

5x5 পর্যন্ত কয়েক সেকেন্ড সময় নেয়, 6x6 এর জন্য কয়েক ঘন্টা।

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;

#define N 6

typedef uint64_t board;

// board is N bits by N bits, with indexes like this (N=4):                                                        
//  0  1  2  3                                                                                                     
//  4  5  6  7                                                                                                     
//  8  9 10 11                                                                                                     
// 12 13 14 15                                                                                                     

#if N==3
#define LEFT_COL (1 + (1<<3) + (1<<6))
#define RIGHT_COL ((1<<2) + (1<<5) + (1<<8))
#define ALL 0x1ffULL
#elif N==4
#define LEFT_COL 0x1111ULL
#define RIGHT_COL 0x8888ULL
#define ALL 0xffffULL
#elif N==5
#define LEFT_COL (1ULL + (1<<5) + (1<<10) + (1<<15) + (1<<20))
#define RIGHT_COL ((1ULL<<4) + (1<<9) + (1<<14) + (1<<19) + (1<<24))
#define ALL 0x1ffffffULL
#elif N==6
#define LEFT_COL (1 + (1<<6) + (1<<12) + (1<<18) + (1<<24) + (1ULL<<30))
#define RIGHT_COL ((1<<5) + (1<<11) + (1<<17) + (1<<23) + (1<<29) + (1ULL<<35))
#define ALL 0xfffffffffULL
#else
#error "bad N"
#endif

static inline board north(board b) {
  return (b >> N) + (b << N*N-N);
}
static inline board south(board b) {
  return (b << N) + (b >> N*N-N);
}
static inline board west(board b) {
  return ((b & ~LEFT_COL) >> 1) + ((b & LEFT_COL) << N-1);
}
static inline board east(board b) {
  return ((b & ~RIGHT_COL) << 1) + ((b & RIGHT_COL) >> N-1);
}

board next(board b) {
  board n1 = north(b);
  board n2 = south(b);
  board n3 = west(b);
  board n4 = east(b);
  board n5 = north(n3);
  board n6 = north(n4);
  board n7 = south(n3);
  board n8 = south(n4);

  // add all the bits bitparallel-y to a 2-bit accumulator with overflow
  board a0 = 0;
  board a1 = 0;
  board overflow = 0;
#define ADD(x) overflow |= a0 & a1 & x; a1 ^= a0 & x; a0 ^= x;

  a0 = n1; // no carry yet
  a1 ^= a0 & n2; a0 ^= n2; // no overflow yet
  a1 ^= a0 & n3; a0 ^= n3; // no overflow yet
  ADD(n4);
  ADD(n5);
  ADD(n6);
  ADD(n7);
  ADD(n8);
  return (a1 & (b | a0)) & ~overflow & ALL;
}
void print(board b) {
  for (int i = 0; i < N; i++) {
    for (int j = 0; j < N; j++) {
      printf("%d", (int)(b >> i*N+j & 1));
    }
    printf(" ");
  }
  if (b >> N*N) printf("*");
  printf("\n");
}

int main(int argc, char *argv[]) {
  // Somewhere in the starting pattern there are a 1 and 0 together.  Using translational                          
  // and rotational symmetry, we can put these in the first two bits.  So we need only consider                    
  // 1 mod 4 boards.                                                                                               

  board steps[10000];
  int maxsteps = -1;
  for (board b = 1; b < 1ULL << N*N; b += 4) {
    int nsteps = 0;
    board x = b;
    while (true) {
      int repeat = steps + nsteps - find(steps, steps + nsteps, x);
      if (repeat > 0) {
        if (repeat == 1 && nsteps > maxsteps) {
          printf("%d: ", nsteps);
          print(b);
          maxsteps = nsteps;
        }
        break;
      }
      steps[nsteps++] = x;
      x = next(x);
    }
  }
}

1
আপনি nextবাছাইয়ের পরিবর্তে গণনা করে মধ্যম উন্নতি পেতে পারেন । #define H(x,y){x^=y;y&=(x^y);}এবং তারপরে কিছুH(n1,n2);H(n3,n4);H(n5,n6);H(n7,n8);H(n1,n3);H(n5,n7);H(n2,n4);H(n6,n8);H(n1,n5);H(n3,n7);H(n2,n6);H(n2,n3);H(n2,n5); return n2 & (b | n1) & ~(n3|n4|n5|n6|n7|n8) & ALL;
পিটার টেলর

সত্যিই শীতল সমাধান!
আলেকজান্ডারসন

@ পিটারটেলর: ধন্যবাদ, আমি গণনা কার্যকর করেছি (এর জন্য একটি পৃথক প্রকল্প), নির্দেশাবলীর একগুচ্ছ সংরক্ষণ করেছি।
কিথ র্যান্ডাল

9

আমি নিম্নলিখিত সম্ভাব্য সমাধানের পন্থাগুলি দেখছি:

  • ভারী তত্ত্ব। আমি জানি একটি লাইনে টরাসে কিছু সাহিত্য রয়েছে তবে আমি এর বেশি পড়িনি।
  • বর্বর বাহিনী ফরোয়ার্ড: প্রতিটি সম্ভাব্য বোর্ডের জন্য, এর স্কোর পরীক্ষা করে। মূলত ম্যাথু এবং কিথের পন্থাগুলি এটিই করে, যদিও কিথ 4 এর গুণক দ্বারা পরীক্ষা করার জন্য বোর্ডগুলির সংখ্যা হ্রাস করে।
    • অপ্টিমাইজেশন: প্রমিত প্রতিনিধিত্ব। যদি আমরা এটি পরীক্ষা করতে পারি যে কোনও বোর্ডের স্কোরটি মূল্যায়ন করতে তার চেয়ে দ্রুত গতিতে উপস্থাপনা রয়েছে কিনা, আমরা প্রায় 8N ^ 2 এর একটি ফ্যাক্টরটির গতি অর্জন করি। (ছোট সমতুল্য শ্রেণীর সাথেও আংশিক পন্থা রয়েছে)।
    • অপ্টিমাইজেশন: ডিপি। প্রতিটি বোর্ডের জন্য স্কোরকে ক্যাশে করুন, যাতে তারা রূপান্তর বা ডাইভার্জ না করা পর্যন্ত কেবল সেগুলি না চালানোর পরিবর্তে আমরা কেবল আগেই দেখেছি এমন বোর্ড না পাওয়া পর্যন্ত আমরা কেবল হাঁটাচলা করি। নীতিগতভাবে এটি গড় স্কোর / চক্র দৈর্ঘ্যের (সম্ভবত 20 বা ততোধিক) দৈর্ঘ্যের একটি উপাদান দ্বারা গতি বাড়িয়ে তুলবে, তবে বাস্তবে আমরা সম্ভবত খুব বেশি অদলবদল করব। উদাহরণস্বরূপ এন = 6 এর জন্য আমাদের 2 ^ 36 স্কোরের জন্য সক্ষমতা প্রয়োজন, যা প্রতি স্কোর বাইটে 16 গিগাবাইট এবং আমাদের এলোমেলো অ্যাক্সেস প্রয়োজন তাই আমরা ভাল ক্যাশে লোকালটি আশা করতে পারি না।
    • দুজনকে একত্রিত করুন। এন = For এর জন্য, সম্পূর্ণ আধ্যাত্মিক উপস্থাপনা আমাদের প্রায় 60 মেগা-স্কোর ডিপি ক্যাশে হ্রাস করতে দেয়। এটি একটি প্রতিশ্রুতিবদ্ধ পদ্ধতির।
  • পিছনে জোর জোর। এটি প্রথমে অদ্ভুত বলে মনে হয়, তবে আমরা যদি ধরে নিই যে আমরা সহজেই প্রাণবন্ত খুঁজে পেতে পারি এবং আমরা সহজেই Next(board)ফাংশনটি উল্টাতে পারি তবে আমরা দেখতে পাচ্ছি যে এর কিছু সুবিধা রয়েছে, যদিও আমি যতটা আশা করি তেমন নয়।
    • আমরা ডাইভারিং বোর্ডগুলি মোটেও বিরক্ত করি না। সংরক্ষণের খুব বেশি নয়, কারণ এগুলি বেশ বিরল।
    • আমাদের সকল বোর্ডের জন্য স্কোর সংরক্ষণ করার দরকার নেই, সুতরাং ফরোয়ার্ড ডিপি পদ্ধতির চেয়ে মেমরির চাপ কম হওয়া উচিত।
    • পিছনের দিকে কাজ করা সাহিত্যে এখনও জীবদ্দশায় গণনার প্রসঙ্গে আমি যে কৌশলটি দেখেছি তার ভিন্নতা দ্বারা বাস্তবে যথেষ্ট সহজ। এটি প্রতিটি কলামকে বর্ণমালার অক্ষর হিসাবে বিবেচনা করে এবং তারপরে পর্যবেক্ষণ করে যে তিনটি বর্ণের ক্রম পরবর্তী প্রজন্মের মধ্যবর্তীটি নির্ধারণ করে। অঙ্কিত স্থিরজীবনের সমান্তরালটি এতটাই নিকটবর্তী যে আমি এগুলিকে কেবলমাত্র কিছুটা বিশ্রী পদ্ধতিতে রিফেক্টর করেছি Prev2
    • মনে হতে পারে আমরা স্থির জীবনকে কেবল ক্যানোনিকালাইজ করতে পারি এবং খুব অল্প ব্যয়ের জন্য 8N ^ 2 স্পিড-আপের মতো কিছু পেতে পারি। তবে, পরীক্ষামূলকভাবে আমরা প্রতিটি পদক্ষেপে ক্যানোনিকালাইজেশন করা থাকলে বোর্ড বিবেচিত বোর্ডগুলিতে এখনও একটি বড় হ্রাস পেয়েছি।
    • আশ্চর্যজনকভাবে বোর্ডের একটি উচ্চতর অনুপাতের স্কোর 2 বা 3 থাকে, সুতরাং এখনও মেমরির চাপ রয়েছে। আমি পূর্বের প্রজন্মের তৈরির পরে ক্যানোনিকালাইজিংয়ের পরিবর্তে ফ্লাইয়ে ক্যানোনিকালাইজেশন করা প্রয়োজনীয় বলে মনে করেছি। প্রস্থের প্রথম সন্ধানের চেয়ে গভীরতা-প্রথম করার মাধ্যমে মেমরির ব্যবহার হ্রাস করা আকর্ষণীয় হতে পারে তবে স্ট্যাককে উপচে না ফেলে এবং অপ্রয়োজনীয় গণনা না করে পূর্ববর্তী বোর্ডগুলি গণনার জন্য একটি সহ-রুটিন / ধারাবাহিকতা পদ্ধতির প্রয়োজন।

আমি মনে করি না যে মাইক্রো-অপ্টিমাইজেশন আমাকে কীথের কোডটি ধরতে দেবে, তবে আগ্রহের জন্য আমি যা আছে তা পোস্ট করব। এটি মনো 2 2.4 বা। নেট (পিআইএনএলকিউ ব্যতীত) এবং পিএনএলকিউ ব্যবহার করে প্রায় 20 সেকেন্ডে 2GHz মেশিনে প্রায় এক মিনিটের মধ্যে এন = 5 সলভ করে; এন = 6 অনেক ঘন্টা চালায়।

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sandbox {
    class Codegolf9393 {
        internal static void Main() {
            new Codegolf9393(4).Solve();
        }

        private readonly int _Size;
        private readonly uint _AlphabetSize;
        private readonly uint[] _Transitions;
        private readonly uint[][] _PrevData1;
        private readonly uint[][] _PrevData2;
        private readonly uint[,,] _CanonicalData;

        private Codegolf9393(int size) {
            if (size > 8) throw new NotImplementedException("We need to fit the bits in a ulong");

            _Size = size;
            _AlphabetSize = 1u << _Size;

            _Transitions = new uint[_AlphabetSize * _AlphabetSize * _AlphabetSize];
            _PrevData1 = new uint[_AlphabetSize * _AlphabetSize][];
            _PrevData2 = new uint[_AlphabetSize * _AlphabetSize * _AlphabetSize][];
            _CanonicalData = new uint[_Size, 2, _AlphabetSize];

            InitTransitions();
        }

        private void InitTransitions() {
            HashSet<uint>[] tmpPrev1 = new HashSet<uint>[_AlphabetSize * _AlphabetSize];
            HashSet<uint>[] tmpPrev2 = new HashSet<uint>[_AlphabetSize * _AlphabetSize * _AlphabetSize];
            for (int i = 0; i < tmpPrev1.Length; i++) tmpPrev1[i] = new HashSet<uint>();
            for (int i = 0; i < tmpPrev2.Length; i++) tmpPrev2[i] = new HashSet<uint>();

            for (uint i = 0; i < _AlphabetSize; i++) {
                for (uint j = 0; j < _AlphabetSize; j++) {
                    uint prefix = Pack(i, j);
                    for (uint k = 0; k < _AlphabetSize; k++) {
                        // Build table for forwards checking
                        uint jprime = 0;
                        for (int l = 0; l < _Size; l++) {
                            uint count = GetBit(i, l-1) + GetBit(i, l) + GetBit(i, l+1) + GetBit(j, l-1) + GetBit(j, l+1) + GetBit(k, l-1) + GetBit(k, l) + GetBit(k, l+1);
                            uint alive = GetBit(j, l);
                            jprime = SetBit(jprime, l, (count == 3 || (alive + count == 3)) ? 1u : 0u);
                        }
                        _Transitions[Pack(prefix, k)] = jprime;

                        // Build tables for backwards possibilities
                        tmpPrev1[Pack(jprime, j)].Add(k);
                        tmpPrev2[Pack(jprime, i, j)].Add(k);
                    }
                }
            }

            for (int i = 0; i < tmpPrev1.Length; i++) _PrevData1[i] = tmpPrev1[i].ToArray();
            for (int i = 0; i < tmpPrev2.Length; i++) _PrevData2[i] = tmpPrev2[i].ToArray();

            for (uint col = 0; col < _AlphabetSize; col++) {
                _CanonicalData[0, 0, col] = col;
                _CanonicalData[0, 1, col] = VFlip(col);
                for (int rot = 1; rot < _Size; rot++) {
                    _CanonicalData[rot, 0, col] = VRotate(_CanonicalData[rot - 1, 0, col]);
                    _CanonicalData[rot, 1, col] = VRotate(_CanonicalData[rot - 1, 1, col]);
                }
            }
        }

        private ICollection<ulong> Prev2(bool stillLife, ulong next, ulong prev, int idx, ICollection<ulong> accum) {
            if (stillLife) next = prev;

            if (idx == 0) {
                for (uint a = 0; a < _AlphabetSize; a++) Prev2(stillLife, next, SetColumn(0, idx, a), idx + 1, accum);
            }
            else if (idx < _Size) {
                uint i = GetColumn(prev, idx - 2), j = GetColumn(prev, idx - 1);
                uint jprime = GetColumn(next, idx - 1);
                uint[] succ = idx == 1 ? _PrevData1[Pack(jprime, j)] : _PrevData2[Pack(jprime, i, j)];
                foreach (uint b in succ) Prev2(stillLife, next, SetColumn(prev, idx, b), idx + 1, accum);
            }
            else {
                // Final checks: does the loop round work?
                uint a0 = GetColumn(prev, 0), a1 = GetColumn(prev, 1);
                uint am = GetColumn(prev, _Size - 2), an = GetColumn(prev, _Size - 1);
                if (_Transitions[Pack(am, an, a0)] == GetColumn(next, _Size - 1) &&
                    _Transitions[Pack(an, a0, a1)] == GetColumn(next, 0)) {
                    accum.Add(Canonicalise(prev));
                }
            }

            return accum;
        }

        internal void Solve() {
            DateTime start = DateTime.UtcNow;
            ICollection<ulong> gen = Prev2(true, 0, 0, 0, new HashSet<ulong>());
            for (int depth = 1; gen.Count > 0; depth++) {
                Console.WriteLine("Length {0}: {1}", depth, gen.Count);
                ICollection<ulong> nextGen;

                #if NET_40
                nextGen = new HashSet<ulong>(gen.AsParallel().SelectMany(board => Prev2(false, board, 0, 0, new HashSet<ulong>())));
                #else
                nextGen = new HashSet<ulong>();
                foreach (ulong board in gen) Prev2(false, board, 0, 0, nextGen);
                #endif

                // We don't want the still lifes to persist or we'll loop for ever
                if (depth == 1) {
                    foreach (ulong stilllife in gen) nextGen.Remove(stilllife);
                }

                gen = nextGen;
            }
            Console.WriteLine("Time taken: {0}", DateTime.UtcNow - start);
        }

        private ulong Canonicalise(ulong board)
        {
            // Find the minimum board under rotation and reflection using something akin to radix sort.
            Isomorphism canonical = new Isomorphism(0, 1, 0, 1);
            for (int xoff = 0; xoff < _Size; xoff++) {
                for (int yoff = 0; yoff < _Size; yoff++) {
                    for (int xdir = -1; xdir <= 1; xdir += 2) {
                        for (int ydir = 0; ydir <= 1; ydir++) {
                            Isomorphism candidate = new Isomorphism(xoff, xdir, yoff, ydir);

                            for (int col = 0; col < _Size; col++) {
                                uint a = canonical.Column(this, board, col);
                                uint b = candidate.Column(this, board, col);

                                if (b < a) canonical = candidate;
                                if (a != b) break;
                            }
                        }
                    }
                }
            }

            ulong canonicalValue = 0;
            for (int i = 0; i < _Size; i++) canonicalValue = SetColumn(canonicalValue, i, canonical.Column(this, board, i));
            return canonicalValue;
        }

        struct Isomorphism {
            int xoff, xdir, yoff, ydir;

            internal Isomorphism(int xoff, int xdir, int yoff, int ydir) {
                this.xoff = xoff;
                this.xdir = xdir;
                this.yoff = yoff;
                this.ydir = ydir;
            }

            internal uint Column(Codegolf9393 _this, ulong board, int col) {
                uint basic = _this.GetColumn(board, xoff + col * xdir);
                return _this._CanonicalData[yoff, ydir, basic];
            }
        }

        private uint VRotate(uint col) {
            return ((col << 1) | (col >> (_Size - 1))) & (_AlphabetSize - 1);
        }

        private uint VFlip(uint col) {
            uint replacement = 0;
            for (int row = 0; row < _Size; row++)
                replacement = SetBit(replacement, row, GetBit(col, _Size - row - 1));
            return replacement;
        }

        private uint GetBit(uint n, int bit) {
            bit %= _Size;
            if (bit < 0) bit += _Size;

            return (n >> bit) & 1;
        }

        private uint SetBit(uint n, int bit, uint value) {
            bit %= _Size;
            if (bit < 0) bit += _Size;

            uint mask = 1u << bit;
            return (n & ~mask) | (value == 0 ? 0 : mask);
        }

        private uint Pack(uint a, uint b) { return (a << _Size) | b; }
        private uint Pack(uint a, uint b, uint c) {
            return (((a << _Size) | b) << _Size) | c;
        }

        private uint GetColumn(ulong n, int col) {
            col %= _Size;
            if (col < 0) col += _Size;
            return (_AlphabetSize - 1) & (uint)(n >> (col * _Size));
        }

        private ulong SetColumn(ulong n, int col, uint value) {
            col %= _Size;
            if (col < 0) col += _Size;

            ulong mask = (_AlphabetSize - 1) << (col * _Size);
            return (n & ~mask) | (((ulong)value) << (col * _Size));
        }
    }
}

আমি নির্দিষ্ট পয়েন্টগুলি থেকে পিছনে হাঁটার জন্য অন্য সংস্করণেও কাজ করছি। আমি ইতিমধ্যে এন = 8 পর্যন্ত স্থির পয়েন্টগুলি গণনা করেছি (এন = 8 এর জন্য ক্যানোনিকালাইজেশনের পূর্বে এর মধ্যে 8439661313 রয়েছে)। আমি একটি সাধারণ পূর্ববর্তী কাজ পেয়েছি, তবে এটি খুব ধীর। সমস্যার অংশটি কেবল আকারের আকারের, এন = 6 এর জন্য খালি বোর্ডে 574384901 পূর্বসূরি রয়েছে (আধ্যাত্মিককরণের আগে)।
কিথ র্যান্ডাল

1
3 দিন এবং 11 ঘন্টা 6x6 এর উত্তর 91 টি তা নিশ্চিত করার জন্য।
পিটার টেলর

1

গুণক

USING: arrays grouping kernel locals math math.functions math.parser math.order math.ranges math.vectors sequences sequences.extras ;
IN: longest-gof-pattern

:: neighbors ( x y game -- neighbors )
game length :> len 
x y game -rot 2array {
    { -1 -1 }
    { -1 0 }
    { -1 1 }
    { 0 -1 }
    { 0 1 }
    { 1 -1 }
    { 1 0 }
    { 1 1 }
} [
    v+ [
        dup 0 <
        [ dup abs len mod - abs len mod ] [ abs len mod ]
        if
    ] map
] with map [ swap [ first2 ] dip nth nth ] with map ;

: next ( game -- next )
dup [
    [
        neighbors sum
        [ [ 1 = ] [ 2 3 between? ] bi* and ]
        [ [ 0 = ] [ 3 = ] bi* and ] 2bi or 1 0 ?
    ] curry curry map-index
] curry map-index ;

: suffixes ( seq -- suffixes )
{ }
[ [ [ suffix ] curry map ] [ 1array 1array ] bi append ]
reduce ;

! find largest repeating pattern
: LRP ( seq -- pattern )
dup length iota
[ 1 + [ reverse ] dip group [ reverse ] map reverse ] with
map dup [ dup last [ = ] curry map ] map
[ suffixes [ t [ and ] reduce ] map [ ] count ] map
dup supremum [ = ] curry find drop swap nth last ;

: game-sequence ( game -- seq )
1array [
    dup [
        dup length 2 >
        [ 2 tail-slice* [ first ] [ last ] bi = not ]
        [ drop t ] if
    ] [ LRP length 1 > not ] bi and
] [ dup last next suffix ] while ;

: pad-to-with ( str len padstr -- rstr )
[ swap dup length swapd - ] dip [ ] curry replicate ""
[ append ] reduce prepend ;

:: all-NxN-games ( n -- games )
2 n sq ^ iota [
    >bin n sq "0" pad-to-with n group
    [ [ 48 = 0 1 ? ] { } map-as ] map
] map ;

: longest-gof-pattern ( n -- game )
all-NxN-games [ game-sequence ] map [ length ] supremum-by but-last ;

কিছু সময়ের পরিসংখ্যান:

IN: longest-gof-pattern [ 3 longest-gof-pattern ] time dup length . . 
Running time: 0.08850873500000001 seconds

3
{
   { { 1 1 1 } { 0 0 0 } { 0 0 0 } }
   { { 1 1 1 } { 1 1 1 } { 1 1 1 } }
   { { 0 0 0 } { 0 0 0 } { 0 0 0 } }
}

IN: longest-gof-pattern [ 4 longest-gof-pattern ] time dup length . . 
Running time: 49.667698828 seconds

10
{
  { { 0 1 1 0 } { 0 1 0 0 } { 0 1 0 0 } { 1 1 0 1 } }
  { { 0 1 1 0 } { 0 1 0 0 } { 0 1 0 0 } { 0 0 0 1 } }
  { { 0 1 1 0 } { 0 1 0 0 } { 0 0 1 0 } { 1 1 0 0 } }
  { { 0 1 1 0 } { 0 1 0 0 } { 0 0 1 0 } { 0 0 0 1 } }
  { { 0 1 1 0 } { 0 1 0 0 } { 0 0 1 0 } { 1 1 0 1 } }
  { { 0 1 1 0 } { 0 1 0 0 } { 0 0 1 1 } { 0 0 0 1 } }
  { { 0 1 0 1 } { 0 1 0 1 } { 0 0 1 1 } { 1 1 0 1 } }
  { { 1 1 0 1 } { 1 1 0 1 } { 0 0 0 0 } { 1 1 0 0 } }
  { { 1 1 0 1 } { 1 1 0 1 } { 0 0 1 1 } { 1 1 1 1 } }
  { { 0 0 0 0 } { 0 0 0 0 } { 0 0 0 0 } { 0 0 0 0 } }
}

এবং 5 টি পরীক্ষা করে REPL ক্র্যাশ করেছে। Hmph। প্রোগ্রামটির সবচেয়ে অদক্ষ অংশটি সম্ভবত ফাংশন গেম-সিকোয়েন্স। আমি পরে এটি আরও ভাল করতে সক্ষম হতে পারে।


শান্ত! আমার মনে হয় আপনার আউটপুটটি 1 খুব বড়, 3x3-প্যাটার্নগুলির জন্য, দীর্ঘতম অ-পুনরাবৃত্তি ক্রমের দৈর্ঘ্য 3 নয়, 4 নয় ...
আলেকজান্দারসন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.