Skip to content

Commit

Permalink
Render solution to canvas - clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
stamselberg committed Jan 12, 2025
1 parent 205f769 commit ed80d49
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 39 deletions.
4 changes: 2 additions & 2 deletions react-app/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
content="Rubiks 2x2 Solver - finding shortest solve"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
Expand All @@ -24,7 +24,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>Rubiks 2x2 Solver</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
Expand Down
28 changes: 7 additions & 21 deletions react-app/src/components/CubeSolutionInfo.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// CubeSolutionInfo.js
import React from 'react';
import { Html } from '@react-three/drei';
import { useCubeContext } from './CubeContext';
import { cubeCorners } from './cubedata.js'
import { solveRubiks2x2 } from './SolveRubiks2x2.js'
import InfoPanel from './InfoPanel.js'

// This is where the solution will go. This class needs to analyse
// the 24 faces, mapping each three to a cube corner (if one exists)
// If all 8 are mapped (and all 8 are used) the solver should activate
// and output the solution
// The HTML needs some work (should not use absolute positioning, should possibly use CSS, or use 3D objects instead)
function CubeSolutionInfo() {
function CubeSolutionInfo({ position }) {
const { cubeColours } = useCubeContext();

// Based on current colours, determine which corner (if any) and rotation in the
Expand Down Expand Up @@ -47,34 +47,20 @@ function CubeSolutionInfo() {

const bAllCornersValid = !lidModelCorners.includes(0);

//const cornerInfo = lidModelCorners.join(' ');
let solution = 'No cube exists that looks like this';

if (bAllCornersValid) {
const lBestPath = solveRubiks2x2(lidModelCorners);
if (lBestPath) {
solution = 'Solution: ' + lBestPath.join(' ');
solution = (lBestPath.length == 0) ? 'Solved' : 'Solution: ' + lBestPath.join(' ');
}
}
position = { x: position[0], y: position[1] };

return (
<Html>
<div
style={{
position: 'absolute',
top: '100px',
left: '-400px',
color: 'white',
zIndex: '1',
}}
>
{solution}
</div>
</Html>
<InfoPanel text={solution} font="48px Arial" position={position} />

);
}




export default CubeSolutionInfo;
export default CubeSolutionInfo;
35 changes: 35 additions & 0 deletions react-app/src/components/InfoPanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useLoader } from '@react-three/fiber';
import { TextureLoader } from 'three';

function InfoPanel({ text, font, position }) {
const texture = useLoader(TextureLoader, createTextCanvas(text, font).toDataURL());

return (
<mesh position={[position.x, position.y, 0]} >
<planeGeometry args={[4, 2]} />
<meshStandardMaterial map={texture} transparent={true} opacity="1" />
</mesh>
);
}


function createTextCanvas(text, font = '48px sans-serif') {
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');

// Set canvas size
canvas.width = 1024;
canvas.height = 512;

// Draw text
context.font = font;
context.fillStyle = '#ddf4ff';
context.textAlign = 'center';
context.textBaseline = 'middle';
context.fillText(text, canvas.width / 2, canvas.height / 2);

return canvas;
}


export default InfoPanel;
20 changes: 8 additions & 12 deletions react-app/src/components/RubiksCorner.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// RubiksCorner.js
import React, { useRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { DoubleSide} from 'three';
import { faceColours, toggleColour } from './colours.js'
import { useCubeContext } from './CubeContext.js';

Expand Down Expand Up @@ -71,24 +70,21 @@ function RubiksCorner({ cubeId, cornerId, scale, border }) {
const handleClickFront = (event) => { handleClick(event, 1) }
const handleClickSide = (event) => { handleClick(event, 2) }
const handleClick = (event, ix) => {
//console.log('Click: cubeId: ', cubeId, 'Corner: ', cornerId, ' face (todo: depends...): ', ix, 'point:', event.point);
const LookUpMap = cubeId == 'LeftStillView' ? LeftStillViewClickableFaces : cubeId == 'RightStillView' ? RightStillViewClickableFaces : null;
const LookUpMap = cubeId === 'LeftStillView' ? LeftStillViewClickableFaces : cubeId === 'RightStillView' ? RightStillViewClickableFaces : null;
if (LookUpMap) {
const lookupPoint = cornerId * 10 + ix;
const lookedUp = LookUpMap.get(lookupPoint);
if (lookedUp) {
//console.log('Accepted: ', lookedUp, lookedUp.name);
// Toggle the colour corresponding to the clicked face

// Toggle the colour corresponding to the clicked face
if (thisCornerData.clockwise && (ix > 0)) {
ix = (ix == 1) ? 2 : 1;
ix = (ix === 1) ? 2 : 1;
}
const newCubeColours = [...cubeColours];

const ixColour = ((cornerId - 1) * 3) + ix;
const oldColour = newCubeColours[ixColour];
const newColour = toggleColour(oldColour);
//console.log('For ', cubeId, '[',cornerId,'].',ix,' changing from ', oldColour, ' to ', newColour);
newCubeColours[ixColour] = newColour;
setCubeColours(newCubeColours);
}
Expand All @@ -101,7 +97,7 @@ function RubiksCorner({ cubeId, cornerId, scale, border }) {
// Handle the clockwise/anticlockwise peculiarity in the data model...
// Map 0=>0 1=>2 and 2=>1
if (thisCornerData.clockwise && (ixFace > 0)) {
ixFace = (ixFace == 1) ? 2 : 1;
ixFace = (ixFace === 1) ? 2 : 1;
}
// Map Corner 1 to ix 012/021 - Corner 2 to 345/354, etc....
const ixColour = ((cornerId - 1) * 3) + ixFace;
Expand All @@ -116,19 +112,19 @@ function RubiksCorner({ cubeId, cornerId, scale, border }) {
{/* Top face */}
<mesh position={[0, thisCornerData.position[1], 0]} rotation={[Math.PI / 2, 0, 0]} onClick={handleClickTop}>
<planeGeometry args={[size, size]} />
<meshBasicMaterial color={getFaceColour(0)} transparent={true} opacity="0.94" side={THREE.DoubleSide} />
<meshBasicMaterial color={getFaceColour(0)} transparent={true} opacity="0.94" side={DoubleSide} />
</mesh>

{/* Front face */}
<mesh position={[0, 0, thisCornerData.position[2]]} onClick={handleClickFront}>
<planeGeometry args={[size, size]} />
<meshBasicMaterial color={getFaceColour(1)} transparent={true} opacity="0.94" side={THREE.DoubleSide} />
<meshBasicMaterial color={getFaceColour(1)} transparent={true} opacity="0.94" side={DoubleSide} />
</mesh>

{/* Right face */}
<mesh position={[thisCornerData.position[0], 0, 0]} rotation={[0, Math.PI / 2, 0]} onClick={handleClickSide}>
<planeGeometry args={[size, size]} />
<meshBasicMaterial color={getFaceColour(2)} transparent={true} opacity="0.94" side={THREE.DoubleSide} />
<meshBasicMaterial color={getFaceColour(2)} transparent={true} opacity="0.94" side={DoubleSide} />
</mesh>

</group>
Expand Down
3 changes: 1 addition & 2 deletions react-app/src/components/RubiksCube.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import React, { useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import RubiksCorner from './RubiksCorner.js'

function RubiksCube({ colours, position, border, cubeRotation, cubeId }) {
function RubiksCube({ position, border, cubeRotation, cubeId }) {
const rubiksCubeRef = useRef();

// Use react-three-fiber's useFrame to rotate the group
useFrame(() => {
if (cubeRotation[0] == "dynamic") {
rubiksCubeRef.current.rotation.x += cubeRotation[1];
Expand Down
4 changes: 2 additions & 2 deletions react-app/src/components/ThreeDScene.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ function ThreeDScene() {
style={{ backgroundColor: 'black', width: '100vw', height: '100vh' }}
camera={{ position: [0, 0, 10], near: 0.1, far: 1000, fov: 45 }}
>
<ambientLight intensity={0.5} />
<ambientLight intensity={1} />
<pointLight position={[10, 10, 10]} />
<CubeProvider>
<RubiksCube cubeId="LeftStillView" border="0.02" position={[-5, 3, -12]} cubeRotation={["fixed", Math.PI / 4, Math.PI / 4]} />
<RubiksCube cubeId="Rotating" border="0.02" position={[ 0, 3, -6]} cubeRotation={["dynamic", 0.0101, 0.0161]} />
<RubiksCube cubeId="RightStillView" border="0.02" position={[ 5, 3, -12]} cubeRotation={["fixed", 5 * Math.PI / 4, Math.PI / 4]} />
<RubiksCube cubeId="SolutionStart" border="0.02" position={[ 0, -1, -6]} cubeRotation={["fixed", Math.PI / 16, Math.PI / 16]} />
<CubeSolutionInfo/>
<CubeSolutionInfo position={[-2.5, -1]} />
</CubeProvider>
</Canvas>
);
Expand Down

0 comments on commit ed80d49

Please sign in to comment.