還在上班?很無聊? 數字華容道暢玩地址 css
開發源碼地址html
年底了。哦,不,要過年了。之前只能一路站到公司的我,今早竟然是坐着過來的。新的一年,總要學一個新東西來迎接新的將來吧,因此選擇了一直未碰的那個聽說是全宇宙最牛逼的前端框架-React,在上下班的地鐵上看了兩天官方教程,so what。光看不練假把式,因而就想着作個什麼,偶然看到一個妹妹發了一條關於玩數字華容道,根本停不下來的朋友圈,這遊戲我在今年的最強大腦看過,可是就看兩小天才在滑呀滑呀滑,感受還不錯,程序猿就該多玩益智類,少玩什麼跳一跳。因而去商店下了個,玩着還行,就是廣告太多,並且只能玩五階如下的,看起不難,一個想法涌於腦上,何不拿這練練手作個Demo,畢竟咱們屬於智慧家族的。閒話扯完,進入正題。本文包含但不只包括如下內容:前端
React:16.2.0react
react-router-dom:4.2.2webpack
webpack:3.8.1git
JS:ES6github
CSS:Scssweb
React教程算法
項目目錄結構(很適合React入門 若是感受不錯,請留下你的star):以下圖所示編程
數字華容道里在外國被稱爲puzzle,譯爲數字推盤,最經典的就是puzzle15的高價懸賞13 15 14局面的解。怎麼玩,一圖勝千言,簡單來講就是講左圖的亂選狀態,滑成右圖所示的順序狀態。我的感受和小時候玩的推箱子有點相似。
其實寫完Demo的隨機序列頁面生成和操做交互就用了一個周天和一個週一夜,但到如今線上這個樣子,又多用了三四個晚上(白天上班,晚上學習,這就是前端的平常),爲何?由於當時基礎版部署到線上,讓女友試一把,結果玩個三階的,都兩分鐘了還在折騰(我最快是18秒還原),怎麼這麼笨,因而搶過來,搗騰,再搗騰,怎麼回事,感受無解啊,因而去百度了一下,在知乎裏看到了這個問題,還真的有無解的狀況,問題地址。看圖,後面還要講(敲黑板)
噢,原來是醬紫。光隨機生成一個亂序數列是不夠的,還得保證這個數列的逆序數爲偶數,嗦嘎。因而在隨機序列的生成中又多加一個過程,判斷序列逆序數奇偶性,並調整。早上地鐵上本身又不斷玩玩測試,三階ok,四階ok,五階ok,而後又一遍,一遍。原覺得這樣就大功告成了,可是出現了這樣的畫面。有圖。誰剛說的四階ok。。。。因而又測試了屢次,發現三階,五階確實ok,但四階確實有Bug。Why,後面本身每開一局,截一張圖,無解的,標記下來,下面就是幾張立功的圖片。
下午年會,領導上面講,本身下面睡。睡得天昏地暗,時過境遷,竟然還在叨叨叨,本身就拿起酒店提供的紙和筆找這些數字間的祕密。首先,這幾組數字都是偶逆序列,前一晚寫的調整奇逆序列爲偶逆序列的代碼是沒有問題的,那問題出在哪了。抓腦摳鼻,抖腳搖頭,那一組圖片來回翻閱,靈光一閃,水哥附身,原來是這樣:空格項都出如今第三行,哦,不,應該是奇數行。爲何呢?又去百度,又看到了上面知乎和豆瓣的正經說瞎話的大神(今生最討此類人,害死個仙人),看到這,我開始懷疑,這句話的正確性。奇數階,格子上下左右移動確實不會改變數列的逆序奇偶性。但偶數階,格子的上下移動是會改變序列的奇偶性的,簡單總結一下:
奇數階(3x3,5x5):上移或下移一個數字,其調換的位置是偶數,因此不改變數列逆序數的奇偶性,因此奇數階,生成的初始隨機數列的逆序數必須爲偶數;
偶數階(4x4,6x6):上移或下移一個數字,其調換的位置是奇數,因此會改變數列逆序數的奇偶性,上下交換一次改變一次奇偶性,交換兩次就回到初始狀態。因此能夠大體這樣理解,偶數的平方仍然爲偶數,其有數字的滑塊個數爲奇數個,因此有一個數字必然會和空滑塊產生位置交換,若是空滑塊位於奇數行(空滑塊是不參於數字序列的逆序數計算的),就會產生2n-1次交換,其會改變數列逆序數的奇偶性;而位於偶數行,就會產生2n次交換,不會改變數列逆序數的奇偶性,因此用一個公式總結就是:(數列初始狀態是否爲偶數) === (空行是否爲偶數),簡單來說就是求這兩個數的異或。最後的代碼流程的實現
方法有不少,但我知道的兩種,這裏分享一下,有知道其餘的,請留言作個評論,讓你們一塊兒進步。
順序數組隨機性調換
思路基本就是,先生成一個順序的1~n的順序數組,而後再經過一個1~n的循環來打亂這個數組,其時間複雜度是O(n)。代碼以下。
export const disorganize = (length) => { const arr = []; let temp; for (var i = 1; i < length; i++) { arr.push(i); } for (i = 0; i < length; i++) { let random = Math.round(Math.random() * (length - 2)); temp = arr[random]; arr[random] = arr[i]; arr[i] = temp; } return arr; };
隨機數生成亂序數組
生成一個隨機數,並判斷其是否在目標數組中已存在,當數組個數爲n時,目的達到。其時間複雜度我不知,代碼以下:
export const randomArr = (length) => { const arr = []; let temp; while(arr.length<(length-1)){ let random = 1+Math.round(Math.random() * (length - 2)); if(random<length && arr.indexOf(random)===-1){ arr.push(random); } } return arr; };
雖然代碼看起比上面的簡單,但其時間複雜度最由是O(f(n),最差狀況未知,因此,方法一更推薦,若是說的有什麼毛病,還請及時指出。
最早想到的就是冒泡排序,由於冒泡排序過程就是判斷兩個數是否逆序,是,就交換,不是,繼續下一組判斷。因此,咱們直接將交換的次數,記爲數列逆序數個數,就達到了想要的效果。固然這個題用其餘排序方法也能達到目的,理解了其排序的原理,就很容易計算數列的逆序性,我這裏是直接用的之前冒泡排序的算法。
const bubbleOrder=(arr)=>{ let i ,j ,count=0; const swap=(tar,lastIndex,newIndex)=>{ let temp = tar[lastIndex]; tar[lastIndex] =tar[newIndex]; tar[newIndex] = temp; count++; } for(i=0;i<arr.length;i++){ for(j=arr.length-1;j>i;j--){ (arr[j]<arr[j-1])&&swap(arr,j-1,j); } } return count; }
秒錶是啥,start-pause-stop-reset,中間的步驟不是必須的,但先後兩步必須。固然方法有不少,但都離不開setTimeout或則setInterval兩個方法,requestAnimation應該也能夠。這裏提供一個本身寫的,固然思路來源於網上,只是用本身的思路表達出來。基於setInterval和Date對象。源碼以下:
const timer=(offsetTime)=>{ //offsetTime爲0時,表示從0開始計,不爲0,表示是暫停後繼續計時 const formatter=(t)=>{ const res =t>9 ? t : '0'+t return res; } let startTime = new Date().getTime(),tPass=0,tOffset=offsetTime||0; this.interId = setInterval(()=> { //this.interId 是組件下面建的一個保持定時器值的,用於暫停和中止 let tNew = new Date().getTime(),ms,sec,min,timeStr; tPass = tOffset +tNew - startTime; ms = Math.floor(tPass/10 % 100); sec = Math.floor((tPass / 1000) % 60); min = Math.floor((tPass / 1000 / 60) % 60); timeStr = formatter(min)+':'+formatter(sec)+':'+formatter(ms); this.tick(timeStr,tPass); },100) } tick(timeStr,tPass){ //這是遊戲頁面一個react組件中的一個用於更新顯示dom的觸發器 this.setState({ timePass:tPass, time:timeStr }) }
用Vue與用React的區別,抱頭痛哭,Vue半年沒上項目了,忘得差很少了,我的觀點(非喜勿噴)。
在整個學習過程當中,將不少教程中敲黑板指出來的坑,又結結實實踩了一遍,如今能夠說影響深入。本身整理了一下,作個小分享,願和我同樣剛入門的,碰見下面的錯誤,不會那麼迷茫
不要在
解釋:這個問題,主要是組件對象的構造constructor中,未在constructor綁定事件處理函數的this指向。這個在教程中是有明確說明的,解決辦法就是constructor()中添加:this.resetClick = this.resetClick.bind(this);
解釋:這個問題,主要是組件對象的構造constructor中,未傳入props對象,致使整個組件對象無props屬性;其實除了理解繼承,理解React組件的生命週期也很重要。
解釋:能夠簡單理解爲SyntheticEvent是react爲瀏覽器兼容寫的一個dom事件代理,除了她原有的那些屬性,你不能私自爲其添加屬性。
這個真的是一個讓人頭疼的東西,太影響交互體驗了。若是作過h5都知道加滑動阻止.而react有他本身的一套事件機制封裝,因此在跟元素直接添加touchmove的preventDefault是不行的。得用最原始的事件寫法寫一個阻止滑動的觸摸事件,以下所示。
componentDidMount() { document.addEventListener('touchmove', (e) => { e.preventDefault(); }, { passive: false }); }
一開始個人遊戲盒子是用的flex佈局,但一考慮,盒子裏面的方塊要滑動效果,我要作滑動的緩動效果,因而又改用了絕對定位佈局,每一個
方塊計算其定位點。但事實證實,我當時確實太菜,我用了state來管理每一個方塊在盒子的位置,但我調整state時,React的virtualDom
會自動計算,並更新dom節點,那我保持整個項目,怎麼才能本身作出緩動效果呢?純CSS不行,請各位大神給點建議。
在放假的前幾個小時,把拖了幾天的文章寫完,有點趕,有不足的地方還請及時指出。關於這個項目,後期本身想繼續優化,作一些功能拓展,好比接入數據記錄,NxM階這樣的玩法,有思路的,還請能分享給我,郵箱:closertb@163.com。在最後,送給2017不曾放棄努力的本身一些鼓勵,願2018年能用更好的發展。也祝各位戰友2018新年快樂,年後再見!!!!