I am trying to use the RIS API from the german railway. I managed to use the one on timetables that seems to be json.
https://developers.deutschebahn.com/db-api-marketplace/apis/product/fahrplan/api/9213#/Fahrplan_101/operation/%2Flocation%2F{name}/get
GET https://apis.deutschebahn.com/db-api-marketplace/apis/fahrplan/v1/location/Berlin
Header:
Accept: application/json
DB-Client-Id: 36fd91806420e2e937a599478a557e06
DB-Api-Key: d8a52f0f66184d80bdbd3a4a30c0cc33
Which using httr I can replicate:
url_location<-"https://apis.deutschebahn.com/db-api-marketplace/apis/fahrplan/v1/location/Bonn"
r<-GET(url_location,
add_headers(Accept="application/json",
`DB-Client-Id` = client_id,
`DB-Api-Key` = api_key))
content(r)
I know want to use another API about stations.
https://developers.deutschebahn.com/db-api-marketplace/apis/product/ris-stations/api/ris-stations#/RISStations_160/operation/%2Fstations/get
GET https://apis.deutschebahn.com/db-api-marketplace/apis/ris-stations/v1/stations?onlyActive=true&limit=100
Header:
Accept: application/vnd.de.db.ris+json
DB-Client-Id: 36fd91806420e2e937a599478a557e06
DB-Api-Key: d8a52f0f66184d80bdbd3a4a30c0cc33
I was hoping that it would work as well just adjusting the Accept:
url_station<-"https://apis.deutschebahn.com/db-api-marketplace/apis/ris-stations/v1/stations?onlyActive=true&limit=100"
r_stations<-GET(url_station,
add_headers(Accept="application/vnd.de.db.ris+json",
`DB-Client-Id` = client_id,
`DB-Api-Key` = api_key))
I recieve some data and the status code is 200. It was 415 before adjusting the Accept
When I am looking at the content using the content function or without it I get the following
> head(content(r_stations), 30)
[1] 7b 22 6f 66 66 73 65 74 22 3a 30 2c 22 6c 69 6d 69 74 22 3a 31 30 30 2c 22 74 6f 74 61 6c
r_stations$status_code
[1] 200
I should get something more like this:
{
"offset": 0,
"limit": 100,
"total": 5691,
"stations": [
{
"stationID": "1",
"names": {
"DE": {
"name": "Aachen Hbf"
}
},
I just need to add type='application/json'
content(r_stations, type='application/json')
I recently bought a 4 DOF (Degree Of Freedom) robotic arm kit. I successfully assembled it and now I want to program the arduino to control it.
I know how to make the servos work using arduino but could not figure out how to move the hand to specific positions.
I tried manually creating a two dimensonal array with rotational values for each motor in degrees. This works but it is very hard to get the values and create the array. Currently I adjusted the values by trial and error.
The array I created manually :
short first[] = { 180 , 80 , 0 , 90 };
short pos[][4] =
{
{ 180 , 80 , 00 , 85 },
{ 180 , 85 , 00 , 80 },
{ 180 , 90 , 00 , 75 },
{ 180 , 95 , 00 , 75 },
{ 180 , 100 , 0 , 70 },
{ 180 , 110 , 0 , 70 },
{ 180 , 115 , 0 , 70 },
{ 180 , 120 , 0 , 65 },
{ 180 , 125 , 0 , 65 },
{ 180 , 130 , 0 , 65 },
{ 180 , 135 , 0 , 65 },
{ 180 , 140 , 0 , 65 },
{ 180 , 145 , 0 , 65 },
{ 180 , 150 , 0 , 65 },
{ 180 , 150 , 0 , 70 },
{ 180 , 150 , 0 , 75 },
{ 180 , 150 , 0 , 80 },
{ 180 , 150 , 0 , 90 },
{ 180 , 145 , 0 , 90 },
{ 180 , 140 , 0 , 90 },
{ 180 , 135 , 0 , 90 },
{ 180 , 130 , 0 , 90 },
{ 180 , 125 , 0 , 90 },
{ 180 , 120 , 0 , 90 },
{ 180 , 115 , 0 , 90 },
{ 180 , 110 , 0 , 90 },
{ 170 , 110 , 0 , 90 },
{ 160 , 110 , 0 , 90 },
{ 150 , 110 , 0 , 90 },
{ 140 , 110 , 0 , 90 },
{ 130 , 110 , 0 , 90 },
{ 130 , 115 , 0 , 90 },
{ 120 , 120 , 0 , 90 },
{ 120 , 125 , 0 , 90 },
{ 120 , 130 , 0 , 90 },
{ 120 , 135 , 0 , 90 },
{ 120 , 137 , 0 , 90 },
{ 120 , 139 , 0 , 90 },
{ 120 , 140 , 0 , 85 },
{ 120 , 140 , 0 , 80 },
{ 120 , 140 , 0 , 75 },
{ 120 , 140 , 0 , 70 },
};
The complete code that I wrote :
/*
* claws - 90 close 75 open
* elbow - 0 to 100
* sholder - 30 to 180
*/
Servo Servos[4];
void setup()
{
Servos[0].attach(3);
Servos[1].attach(5);
Servos[2].attach(9);
Servos[3].attach(11);
reset();
run();
Servos[0].detach();
Servos[1].detach();
Servos[2].detach();
Servos[3].detach();
}
void run()
{
for(int i=0; i<sizeof(pos) / sizeof(short) /4 ; i++)
{
for(int j=3; j>=0; j--)
{
Servos[j].write(pos[i][j]);
delay(15);
}
delay(15);
}
for(int i=-1+ sizeof(pos) / sizeof(short) /4;i>=0 ; i--)
{
for(int j=3; j>=0; j--)
{
Servos[j].write(pos[i][j]);
delay(15);
}
delay(15);
}
delay(3000);
}
void reset()
{
for(int i=3; i>=0; i--)Servos[i].write(first[i]);
}
void loop(){}
I want some function to calculate the values of the array for any given coordinate or something like that.(That is the moves of each servo to position the end of the arm at that point)
Photo of the Arm :
Here is the product page of the actual arm :
https://www.amazon.in/gp/product/B07LDNY9J3/ref=ppx_yo_dt_b_asin_title_o03_s00?ie=UTF8&psc=1
I finally solved the problem ! I tried figuring out the inverse kinematics for the arms but I found out it is very hard and due to the uncertainty in the hardware it doesn't work good either. The actual solution was to use sensors. I put distance sensors (Ultra-sonic) on the arm so that I can measure distance between arm parts in real time. Since I know the length of each segment of the arm (I don't have to worry about uncertainty here.) and also the distance between them I can do simple trigonometry to calculate the coordinates of the tip of the arm. This means that I can simply use a feedback loop to position the arm with ineradicable accuracy and overcome the limitations of the Hardware.
I do understand that this is not the exact answer for the asked question but I found out from my experience that this method is the most suitable for the situation (When compared to the attempt according to the question).
I have some asn.1 encoded data. I have some success decoding it with bouncycastle but I hit the wall with quite complex example. It must be doable, but can't get further, hope you could help me, here is the example data:
A1 81 A9 02 02 1C 1F 02 01 15 30 81 9F 55 02 01 14 A0 81 98 A4 81 95 6B 10 30 0E 80 04 00 00 01 1F A1 06 30 04 80 02 33 32 63 06 30 04 80 02 33 32 61 0E 30 0C 80 0A 30 32 32 33 37 38 33 36 31 30 62 06 30 04 80 02 33 32 64 02 87 00 6B 13 30 11 80 04 00 00 01 1F A1 09 30 07 80 05 23 23 37 30 30 4E 01 02 0A 01 16 67 12 30 10 A3 0E 81 0C 2B 34 38 32 32 33 37 38 33 36 31 30 68 0F 30 0D A3 0B 82 09 32 32 38 36 35 33 33 39 38 65 09 30 07 80 05 23 23 37 30 30 7E 12 A0 10 18 0E 32 30 31 36 30 33 30 32 32 32 30 31 33 36
CSTA Browser decoded:
rOSE.roiv-apdu
{ -- SEQUENCE --
invokeID = 7199,
operation-value = 21 (cSTAEventReport),
argument
{ -- SEQUENCE --
crossRefIdentifier = '01 14'H,
eventSpecificInfo.callControlEvents.delivered
{ -- SEQUENCE --
connection.both
{ -- SEQUENCE --
callID = '00 00 01 1F'H,
deviceID.staticID
{ -- SEQUENCE --
deviceIdentifier.dialingNumber = "32" '33 32'H
}
},
alertingDevice.deviceIdentifier
{ -- SEQUENCE --
deviceIdentifier.dialingNumber = "32" '33 32'H
},
callingDevice.deviceIdentifier
{ -- SEQUENCE --
deviceIdentifier.dialingNumber = "0223783610" '30 32 32 33 37 38 33 36 31 30'H
},
calledDevice.deviceIdentifier
{ -- SEQUENCE --
deviceIdentifier.dialingNumber = "32" '33 32'H
},
lastRedirectionDevice.notKnown NULL,
originatingNIDConnection.both
{ -- SEQUENCE --
callID = '00 00 01 1F'H,
deviceID.staticID
{ -- SEQUENCE --
deviceIdentifier.dialingNumber = "##700" '23 23 37 30 30'H
}
},
localConnectionInfo = 2 (alerting),
cause = 22 (newCall),
networkCallingDevice.deviceIdentifier
{ -- SEQUENCE --
deviceIdentifier.explicitPublic.international = "+48223783610" '2B 34 38 32 32 33 37 38 33 36 31 30'H
},
networkCalledDevice.deviceIdentifier
{ -- SEQUENCE --
deviceIdentifier.explicitPublic.national = "228653398" '32 32 38 36 35 33 33 39 38'H
},
associatedCallingDevice.deviceIdentifier
{ -- SEQUENCE --
deviceIdentifier.dialingNumber = "##700" '23 23 37 30 30'H
},
extensions
{ -- SEQUENCE --
security
{ -- SEQUENCE --
timestamp = "20160302220136" '32 30 31 36 30 33 30 32 32 32 30 31 33 36'H
}
}
}
}
}
bouncycastle's dump produces something like that:
00 AC A1 81 A9 02 02 5F B9 02 01 15 30 81 9F 55 02 01 91 A0 81 98 A4 81 95 6B 10 30 0E 80 04 00 00 03 98 A1 06 30 04 80 02 33 32 63 06 30 04 80 02 33 32 61 0E 30 0C 80 0A 30 32 32 33 37 38 33 36 31 30 62 06 30 04 80 02 33 32 64 02 87 00 6B 13 30 11 80 04 00 00 03 98 A1 09 30 07 80 05 23 23 37 30 30 4E 01 02 0A 01 16 67 12 30 10 A3 0E 81 0C 2B 34 38 32 32 33 37 38 33 36 31 30 68 0F 30 0D A3 0B 82 09 32 32 38 36 35 33 33 39 38 65 09 30 07 80 05 23 23 37 30 30 7E 12 A0 10 18 0E 32 30 31 36 30 33 30 34 31 35 32 32 34 30
buf:Tagged [1] IMPLICIT
Sequence
Integer(24505)
Integer(21)
DER Sequence
DER ApplicationSpecific[21] (0191)
Tagged [0]
Tagged [4] IMPLICIT
Sequence
DER ApplicationSpecific[11]
Sequence
Tagged [0] IMPLICIT
DER Octet String[4]
Tagged [1]
DER Sequence
Tagged [0] IMPLICIT
DER Octet String[2]
DER ApplicationSpecific[3]
Sequence
Tagged [0] IMPLICIT
DER Octet String[2]
DER ApplicationSpecific[1]
Sequence
Tagged [0] IMPLICIT
DER Octet String[10]
DER ApplicationSpecific[2]
Sequence
Tagged [0] IMPLICIT
DER Octet String[2]
DER ApplicationSpecific[4]
Tagged [7] IMPLICIT
DER Octet String[0]
DER ApplicationSpecific[11]
Sequence
Tagged [0] IMPLICIT
DER Octet String[4]
Tagged [1]
DER Sequence
Tagged [0] IMPLICIT
DER Octet String[5]
DER ApplicationSpecific[14] (02)
DER Enumerated(22)
DER ApplicationSpecific[7]
Sequence
Tagged [3]
Tagged [1] IMPLICIT
DER Octet String[12]
DER ApplicationSpecific[8]
Sequence
Tagged [3]
Tagged [2] IMPLICIT
DER Octet String[9]
DER ApplicationSpecific[5]
Sequence
Tagged [0] IMPLICIT
DER Octet String[5]
DER ApplicationSpecific[30]
Tagged [0]
GeneralizedTime(20160304152240GMT+01:00)
and I am trying to parse it:
protected void parse() {
logger.trace("Executing parse()");
try {
ASN1InputStream input = new ASN1InputStream(asn1Data);
ASN1Primitive p;
if ((p = input.readObject()) != null) {
ASN1TaggedObject o1 = ASN1TaggedObject.getInstance(p);
ASN1Sequence s1 = ASN1Sequence.getInstance(o1.getObject());
invokeID = Integer.parseInt(s1.getObjectAt(0).toString());
operationValue = Integer.parseInt(s1.getObjectAt(1).toString());
DERSequence ders = (DERSequence) DERSequence.getInstance(s1.getObjectAt(2));
DERApplicationSpecific das = (DERApplicationSpecific) ders.getObjectAt(0);
crossRefIdentifier = das.getContents();
//here are some experiments, but can't get the right objects I could parse / walk through
ASN1TaggedObject o2 = ASN1TaggedObject.getInstance(ders.getObjectAt(1));
DERTaggedObject dto = (DERTaggedObject) o2.getObject();
ASN1Sequence s2 = ASN1Sequence.getInstance(dto.getObject());
DERApplicationSpecific das1 = (DERApplicationSpecific) s2.getObjectAt(0);
ASN1Sequence s3 = (ASN1Sequence) das1.getObject();
}
} catch (Exception ex) {
logger.warn("exception while parsing ASN1 data", ex);
}
}
as you can see I've been able to decode some basic tags (ie. invokeID, operation-value and crossRefIdentifier) but can't get deeper in the tree (callId, callingNumber ...).
If you have experience in that matter I would appreciate your help.
It is a very complex ASN.1 object. There are several places where it could go wrong with another sample due to structure differences. Here is an example.
using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1;
namespace Asn1ParseBouncy
{
class Program
{
static void Main(string[] args)
{
var bytes2Parse = File.ReadAllBytes(#"c:\a.req");
// (0,169) CONTEXT SPECIFIC(1)
DerTaggedObject rootObj = (DerTaggedObject)Asn1Object.FromByteArray(bytes2Parse);
if (rootObj.TagNo == 1)
{
ParseAtRootLevel(rootObj);
}
else
{
throw new Exception("Expected Tag number to be 1");
}
}
private static void ParseAtRootLevel(DerTaggedObject rootObj)
{
// SEQUENCE under CONTEXT SPECIFIC(1)
var seq = (Asn1Sequence)rootObj.GetObject();
IEnumerator e = seq.GetEnumerator();
bool hasNext;
hasNext = e.MoveNext();
// (3,2) INTEGER -> invokeID
{
Asn1Encodable obj;
if (!hasNext)
{
throw new Exception("more entries expected in sequence");
}
obj = (Asn1Encodable)e.Current;
// TODO: put in a property of class that represents whole ASN.1 message
var invokeID = DerInteger.GetInstance(obj);
hasNext = e.MoveNext();
}
// (7,1) INTEGER -> operation-value
{
Asn1Encodable obj;
if (!hasNext)
{
throw new Exception("more entries expected in sequence");
}
obj = (Asn1Encodable)e.Current;
// TODO: put in a property of class that represents whole ASN.1 message
var operationValue = DerInteger.GetInstance(obj);
hasNext = e.MoveNext();
}
// (10,159) SEQUENCE -> argument
{
Asn1Encodable obj;
if (!hasNext)
{
throw new Exception("more entries expected in sequence");
}
obj = (Asn1Encodable)e.Current;
var argumentSeq = Asn1Sequence.GetInstance(obj);
// argumentData is parsed asn.1 object - argument
var argumentData = ParseArgumentData(argumentSeq);
hasNext = e.MoveNext();
}
if (hasNext)
{
throw new Exception("no more entries expected in sequence");
}
}
private static object ParseArgumentData(Asn1Sequence argumentSeq)
{
IEnumerator e = argumentSeq.GetEnumerator();
bool hasNext;
hasNext = e.MoveNext();
// (13,2) APPLICATION (21) -> crossRefIdentifier
{
Asn1Encodable obj;
if (!hasNext)
{
throw new Exception("more entries expected in sequence");
}
obj = (Asn1Encodable)e.Current;
var crossRefIdentifierAppSpecific = (DerApplicationSpecific)obj;
if (crossRefIdentifierAppSpecific.ApplicationTag != 21)
throw new Exception("Expected application tag 21");
// TODO: put in a property of class that represents whole ASN.1 message
var crossRefIdentifier = crossRefIdentifierAppSpecific.GetContents();
hasNext = e.MoveNext();
}
// (17,152) CONTEXT SPECIFIC (0) -> eventSpecificInfo.callControlEvents.delivered
{
Asn1Encodable obj;
if (!hasNext)
{
throw new Exception("more entries expected in sequence");
}
obj = (Asn1Encodable)e.Current;
var eventSpecificInfo = ((DerTaggedObject)obj);
if (eventSpecificInfo.TagNo != 0)
throw new Exception("Expected Context specific tag number to be 0");
// TODO: put in a property of class that represents whole ASN.1 message
var eventSpecificInfoData = ParseEventSpecificInfo(eventSpecificInfo);
hasNext = e.MoveNext();
}
if (hasNext)
{
throw new Exception("no more entries expected in sequence");
}
// TODO: return parsed values in some class
return null;
}
private static object ParseEventSpecificInfo(DerTaggedObject obj)
{
// still (17,152) CONTEXT SPECIFIC (0)
var connectionBothData = ParseConnectionBoth(obj);
return connectionBothData;
}
private static object ParseConnectionBoth(DerTaggedObject connectionBoth)
{
// (20,149) CONTEXT SPECIFIC (4)->connection.both
var connectionBothTagged = (DerTaggedObject)connectionBoth.GetObject();
if (connectionBothTagged.TagNo != 4)
throw new Exception("Expected Context specific tag number to be 4");
// Sequence under (20,149) CONTEXT SPECIFIC (4) -> connection.both
var connectionBothSeq = (DerSequence)connectionBothTagged.GetObject();
IEnumerator e = connectionBothSeq.GetEnumerator();
bool hasNext;
hasNext = e.MoveNext();
// callID
{
Asn1Encodable obj;
if (!hasNext)
{
throw new Exception("more entries expected in sequence");
}
obj = (Asn1Encodable)e.Current;
// (23,16) APPLICATION (11)
// TODO: put in a property of class that represents whole ASN.1 message
var callIDTagged = (DerApplicationSpecific)obj;
if (callIDTagged.ApplicationTag != 11)
throw new Exception("Expected tag number 11");
// (25,14) SEQUENCE
var callIdSeq = callIDTagged.GetObject().GetDerEncoded();
// TODO: parse CallIdSeq -> (27,4) ContextSpecific(0), (33,6) ContextSpecific(1)
hasNext = e.MoveNext();
}
// TODO: continue with (41,6) Application (3)
// TODO: continue with (49,14) Application (1)
// TODO: continue with (65,6) Application (2)
// etc.
// TOOD: return something useful
throw new NotImplementedException();
}
}
}
I placed notes in the code sample according to dump from ASN.1 Editor
You could make your life a lot easier if you had ASN.1 definition of the object. With help from Binary Notes you could generate classes to parse ASN.1 data object.
I am using Qt5 on Windows7 platform.
In my current app I need a timer to fire every minute ("per minute"), from minute 00 to 59...
I have experimented various ideas, but my (previous) solutions had some issues like: misfire (no timeout triggered for a certain minute) or double-fire (timeout triggered twice for the same minute!).
Finally, I currently reached to this implementation:
static QTimer timer;
static int GetInterval()
{
QDateTime now(QDateTime::currentDateTime());
return ((60 - now.time().second()) * 1000 - now.time().msec());
}
void TEST_TIMER(void)
{
QObject::connect(&timer, &QTimer::timeout, []()
{
qDebug() << " Triggered! " << QDateTime::currentDateTime().time().minute()
<< QDateTime::currentDateTime().time().second()
<< QDateTime::currentDateTime().time().msec();
timer.start(GetInterval());
} );
timer.start(GetInterval());
}
And here is the output:
Triggered! 34 59 550
Triggered! 35 0 3
Triggered! 36 0 15
Triggered! 37 0 28
Triggered! 38 0 41
Triggered! 39 0 54
Triggered! 40 0 68
Triggered! 41 0 82
Triggered! 42 0 97
Triggered! 43 0 109
Triggered! 44 0 123
Triggered! 45 0 137
Triggered! 46 0 149
Triggered! 47 0 165
Triggered! 48 0 178
Triggered! 49 0 192
Triggered! 50 0 205
Triggered! 51 0 217
Triggered! 52 0 231
Triggered! 53 0 244
...
Seems ok, except the first line: Triggered! 34 59 550 :( Why?
Also, why is there that up-drift of about 12-13 msecs/minute?.
So, not being expert in this matter I prefer to ask:
Is this implementation ok? Can it be improved to avoid unpleasant situations like double-fire and/or misfire?
From QTimer description (Qt::CoarseTimer being the default):
For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QTimer may wake up
earlier than expected, within the margins for those types: 5% of the
interval for Qt::CoarseTimer and 500 ms for Qt::VeryCoarseTimer.
So with a 5% accurary, your first shot can be much earlier than expected, and that explains:
Triggered! 34 59 550
Triggered! 35 0 3
If the timer shots (just) before the 0 minute, it will shoot again to align to the minute that's not yet reached, even if it's a few milliseconds away.
If you use a Qt::PreciseTimer instead, it will never time out earlier than expected, so you won't have this problem (pad the delay with a few ms to be sure).
The Qt::CoarseTimer also probably explains the small drift you're seeing, as nothing states that the error margin is random.
I need a timer to fire every minute
Why not keep things simple?
QTimer* pTimer = new QTimer;
connect(pTimer, &QTimer::timeout, [=](){
// do something
};
// fire every 60 seconds
// 1 * 1000 is every second
pTimer->Start(1 * 1000 * 60)
Note that a timer will keep firing, unless you set setSingleShot(true), stop the timer, or delete it.
Just a matter of curiosity, is the Gray code defined for bases other than base two?
I tried to count in base 3, writing consecutive values paying attention to change only one trit at a time. I've been able to enumerate all the values up to 26 (3**3-1) and it seems to work.
000 122 200
001 121 201
002 120 202
012 110 212
011 111 211
010 112 210
020 102 220
021 101 221
022 100 222
The only issue I can see, is that all three trits change when looping back to zero. But this is only true for odd bases. When using even bases looping back to zero would only change a single digit, as in binary.
I even guess it can be extended to other bases, even decimal. This could lead to another ordering when counting in base ten ... :-)
0 1 2 3 4 5 6 7 8 9 19 18 17 16 15 14 13 12 11 10
20 21 22 23 24 25 26 27 28 29 39 38 37 36 35 34 33 32 31 30
Now the question, has anyone ever heard of it? Is there an application for it? Or it is just mathematical frenzy?
Yes. Have a look at the Gray code article at wikipedia. It has a section on n-ary Gray Code.
There are many specialized types of Gray codes other than the binary-reflected Gray code. One such type of Gray code is the n-ary Gray code, also known as a non-Boolean Gray code. As the name implies, this type of Gray code uses non-Boolean values in its encodings.
Just for completeness (as aioobe already gave the right answer), here's a C++ program that lists all the 168 2-digit gray codes for base 3 that start with 00 and marks the 96 cyclic ones. Using the algorithm from Wikipedia, you can construct longer Gray codes easily for even bases. For uneven bases, you can change the program to generate according Gray codes.
The first cyclic 2-digit gray code found with this program is this one:
00 01 02 12 10 11 21 22 20
After changing the program, the first cyclic 3-digit gray found is this:
000 001 002 012 010 011 021 020 022 122 102 100 101 111
110 112 212 202 222 220 120 121 221 201 211 210 200
Code:
#include <stdio.h>
#include <stdlib.h>
// Highest number using two trits
#define MAXN 9
int gray_code_count, cyclic_count;
bool changes_one_trit(int code1, int code2) {
int trits_changed = 0;
if ((code1 / 3) != (code2 / 3)) trits_changed++;
if ((code1 % 3) != (code2 % 3)) trits_changed++;
return (trits_changed == 1);
}
int generate_gray_code(int* code, int depth) {
bool already_used;
if (depth == MAXN) {
for (int i = 0; i < MAXN; i++) {
printf("%i%i ", code[i]/3, code[i]%3);
}
// check if cyclic
if (changes_one_trit(code[MAXN-1], 0)) {
printf("cyclic");
cyclic_count++;
}
printf("\n");
gray_code_count++;
}
// Iterate through the codes that only change one trit
for (int i = 0; i < MAXN; i++) {
// Check if it was used already
already_used = false;
for (int j = 0; j < depth; j++) {
if (code[j] == i) already_used = true;
}
if (already_used) continue;
if (changes_one_trit(code[depth-1], i)) {
code[depth] = i;
generate_gray_code(code, depth + 1);
}
}
}
int main() {
int* code = (int*)malloc(MAXN * sizeof(int));
code[0] = 0;
gray_code_count = 0;
generate_gray_code(code, 1);
printf("%i gray codes found, %i of them are cyclic\n", gray_code_count, cyclic_count);
free(code);
}