Skip to content

Instantly share code, notes, and snippets.

@mritunjayupadhyay
Last active May 30, 2017 14:06
Show Gist options
  • Save mritunjayupadhyay/35748ed2328edf434ae4aebb783f4ca5 to your computer and use it in GitHub Desktop.
Save mritunjayupadhyay/35748ed2328edf434ae4aebb783f4ca5 to your computer and use it in GitHub Desktop.
export const CREATEOPTIONS = 'CREATEOPTIONS';
export const FILLPUZZLE = 'FILLPUZZLE';
export const createOptions = (opts, wordList) => {
const options = {};
options.width = opts.width || wordList[0].length;
options.height = opts.height || wordList[0].length;
options.preferOverlap = opts.preferOverlap === undefined ? true : opts.preferOverlap;
options.fillBlanks = opts.fillBlanks === undefined ? true : opts.fillBlanks;
options.maxattempts = opts.maxattempts || 3;
return {
type: CREATEOPTIONS,
payload: options
};
};
export const fillPuzzle = (puzzle) => {
return {
type: FILLPUZZLE,
payload: puzzle
};
};
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createOptions, fillPuzzle } from '../actions/index.js';
class NewPuzzle extends Component {
constructor(props) {
super(props);
this.myobj = {
startSquare: null,
selectedSquares: [],
curWord: '',
curOrientation: null,
puzzleCons: ''
};
this.fillPuzzle = this.fillPuzzle.bind(this);
this.findBestLocations = this.findBestLocations.bind(this);
this.pruneLocations = this.pruneLocations.bind(this);
this.placeWord = this.placeWord.bind(this);
this.placeWordInPuzzle = this.placeWordInPuzzle.bind(this);
this.fillBlanks = this.fillBlanks.bind(this);
}
componentWillMount() {
let puzzle;
let attempts = 0;
const wordList = this.props.words.slice(0).sort((a, b) =>
((b.length - a.length > 0) ? 1 : -1) || b.localCompare(a));
const opts = this.props.settings || {};
this.props.createOptions(opts, wordList);
const options = {};
options.width = opts.width || wordList[0].length;
options.height = opts.height || wordList[0].length;
options.orientations = opts.orientations || this.props.allMyOrientations.allOrientation;
options.preferOverlap = opts.preferOverlap === undefined ? true : opts.preferOverlap;
options.fillBlanks = opts.fillBlanks === undefined ? true : opts.fillBlanks;
options.maxattempts = opts.maxattempts || 3;
while (!puzzle) {
while (!puzzle && attempts++ < options.maxattempts) {
puzzle = this.fillPuzzle(wordList, options, this.props.allMyOrientations);
}
if (!puzzle) {
options.width++;
options.height++;
attempts = 0;
}
}
if (options.fillBlanks) {
this.fillBlanks(puzzle);
}
this.props.fillPuzzle(puzzle);
}
fillBlanks(puzzle) {
for (let i = 0; i < puzzle.length; i++) {
const row = puzzle[i];
for (let j = 0; j < row.length; j++) {
if (puzzle[i][j] === '') {
puzzle[i][j] = this.props.letters[Math.floor(Math.random() * this.props.letters.length)];
}
}
}
}
findBestLocations(puzzle, options, word, allMyOrientations) {
const locations = [];
const width = options.width;
const height = options.height;
const wordLength = word.length;
let maxOverlap = 0;
for (let k = 0; k < options.orientations.length; k++) {
const orientation = options.orientations[k];
const check = allMyOrientations.checkOrientations[orientation];
const next = allMyOrientations.orientations[orientation];
const skipTo = allMyOrientations.skipOrientations[orientation];
let x = 0;
let y = 0;
let overlap;
while (y < height) {
if (check(x, y, width, height, wordLength)) {
overlap = this.checkForOverLap(puzzle, word, x, y, next);
if (overlap >= maxOverlap || (!options.preferOverlap && overlap > -1)) {
maxOverlap = overlap;
locations.push({
x,
y,
orientation,
overlap
});
}
x++;
if (x >= width) {
x = 0;
y++;
}
} else {
const nextPossible = skipTo(x, y, wordLength);
x = nextPossible.x;
y = nextPossible.y;
}
}
}
return options.preferOverlap ?
this.pruneLocations(locations, maxOverlap) :
locations;
}
checkForOverLap(puzzle, word, x, y, fn) {
let overlap = 0;
for (let k = 0; k < word.length; k++) {
const next = fn(x, y, k);
const score = puzzle[next.x][next.y];
if (score === word[k]) {
overlap++;
} else if (score !== '') {
return -1;
}
}
return overlap;
}
pruneLocations(locations, overlap) {
const pruned = [];
for (let i = 0, len = locations.length; i < len; i++) {
if (locations[i].overlap >= overlap) {
pruned.push(locations[i]);
}
}
return pruned;
}
placeWord(puzzle, word, x, y, fn) {
for (let i = 0; i < word.length; i++) {
const next = fn(x, y, i);
puzzle[next.x][next.y] = word[i];
}
}
placeWordInPuzzle(puzzle, options, word, allMyOrientations) {
const locations = this.findBestLocations(puzzle, options, word, allMyOrientations);
if (locations.length === 0) {
return false;
}
const s = locations[Math.floor(Math.random() * locations.length)];
this.placeWord(puzzle, word, s.x, s.y, allMyOrientations.orientations[s.orientation]);
return true;
}
fillPuzzle(words, options, allMyOrientations) {
let puzzle = [];
for (let i = 0; i < options.height; i++) {
puzzle.push([]);
for (let j = 0; j < options.width; j++) {
puzzle[i].push('');
}
}
for (let k = 0; k < words.length; k++) {
if (!this.placeWordInPuzzle(puzzle, options, words[k], allMyOrientations)) {
return null;
}
}
return puzzle;
}
consolePuzzle() {
if (!this.props.puzzle) {
console.log('no Puzzle formed');
} else {
for (let i = 0; i < this.props.puzzle.length; i++) {
const row = this.props.puzzle[i];
for (let j = 0; j < row.length; j++) {
const p = row[j] + ' ';
this.myobj.puzzleCons += p;
}
this.myobj.puzzleCons += '\n';
}
}
console.log(this.myobj.puzzleCons);
}
render() {
return (
<div
className="word-box" onMouseUp={(e) => this.endTurn(e)}
>
<div className="game-box">
{this.consolePuzzle()}
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
words: state.PuzzleData.words,
settings: state.PuzzleData.settings,
opts: state.PuzzleData.opts,
allMyOrientations: state.PuzzleData,
letters: state.PuzzleData.letters,
puzzle: state.PuzzleData.puzzle
};
}
export default connect(mapStateToProps, { createOptions, fillPuzzle })(NewPuzzle);
import { combineReducers } from 'redux';
import newPuzzleReducer from './newpuzzle_reducer.js';
const rootReducer = combineReducers({
PuzzleData: newPuzzleReducer
});
export default rootReducer;
import { CREATEOPTIONS, FILLPUZZLE } from '../actions/index.js';
const INITIAL_STATE = {
letters: 'abcdefghijklmnopqrstuvwxyz',
allOrientation: ['horizontal', 'horizontalBack', 'vertical',
'verticalUp', 'diagonal', 'diagonalUp', 'diagonalBack', 'diagonalUpBack'],
orientations: {
horizontal: (x, y, l) => {
return {
x: x + l,
y
};
},
horizontalBack: (x, y, l) => {
return {
x: x - l,
y
};
},
vertical: (x, y, l) => {
return {
x,
y: y + l
};
},
verticalUp: (x, y, l) => {
return {
x,
y: y - l
};
},
diagonal: (x, y, l) => {
return {
x: x + l,
y: y + l
};
},
diagonalUp: (x, y, l) => {
return {
x: x + l,
y: y - l
};
},
diagonalBack: (x, y, l) => {
return {
x: x - l,
y: y + l
};
},
diagonalUpBack: (x, y, l) => {
return {
x: x - l,
y: y - l
};
}
},
checkOrientations: {
horizontal: (x, y, w, h, l) => {
return w >= x + l;
},
horizontalBack: (x, y, w, h, l) => {
return x + 1 >= l;
},
vertical: (x, y, w, h, l) => {
return h >= y + l;
},
verticalUp: (x, y, w, h, l) => {
return y + 1 >= l;
},
diagonal: (x, y, w, h, l) => {
return (w >= x + l && h >= y + l);
},
diagonalUp: (x, y, w, h, l) => {
return (w >= x + l && y + 1 >= l);
},
diagonalBack: (x, y, w, h, l) => {
return (x + 1 >= l && h >= y + l);
},
diagonalUpBack: (x, y, w, h, l) => {
return (x + 1 >= l && y + 1 >= l);
}
},
skipOrientations: {
horizontal: (x, y, l) => {
return {
x: 0,
y: y + 1
};
},
horizontalBack: (x, y, l) => {
return {
x: l - 1,
y
};
},
vertical: (x, y, l) => {
return {
x,
y: y + 100
};
},
verticalUp: (x, y, l) => {
return {
x: 0,
y: l - 1
};
},
diagonal: (x, y, l) => {
return {
x: 0,
y: y + 1
};
},
diagonalUp: (x, y, l) => {
return {
x: 0,
y: y < l - 1 ? l - 1 : y + 1
};
},
diagonalBack: (x, y, l) => {
return {
x: l - 1,
y: x < l - 1 ? y : y + 100
};
},
diagonalUpBack: (x, y, l) => {
return {
x: l - 1,
y: x >= l - 1 ? l - 1 : y
};
}
},
words: ['sugar', 'alchemy', 'cows', 'tracks', 'arrived', 'located', 'sir', 'seat',
'sail', 'rolled', 'bear', 'wonder', 'smiled', 'angle', 'absent',
'decadent', 'excellent', 'frequent', 'impatient', 'cell',
'respiration'
],
settings: null,
puzzle: null,
opts: null,
fillBlanks: null
};
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case CREATEOPTIONS: {
return { ...state, opts: action.payload };
}
case FILLPUZZLE: {
return { ...state, puzzle: action.payload };
}
default:
return state;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment